home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dc1 / asm1.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  60KB  |  2,744 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  ASM1.C
  9.  *
  10.  *  Contains routine that actually generate assembly output.  Any given
  11.  *  asm_ routine is only allow to allocate one data and one address register
  12.  *
  13.  *  Note: avoid storing a temporary into the destination and then running an
  14.  *  operation on the destination when one of the sources uses the destination.
  15.  *  e.g.    ptr = *ptr + 2
  16.  */
  17.  
  18. /*
  19. **    $Filename: asm1.c $
  20. **    $Author: dice $
  21. **    $Revision: 30.326 $
  22. **    $Date: 1995/12/24 06:09:34 $
  23. **    $Log: asm1.c,v $
  24.  * Revision 30.326  1995/12/24  06:09:34  dice
  25.  * .
  26.  *
  27.  * Revision 30.156  1995/01/11  05:04:36  dice
  28.  * Added GlobalRegReserved, which serves real function and is also used to
  29.  * implement the MINIDICE hacker-did-the-obvious-thing thing.
  30.  *
  31.  * Revision 30.6  1994/08/04  04:49:26  dice
  32.  * .
  33.  *
  34.  * Revision 30.5  1994/06/13  18:37:20  dice
  35.  * rco_move returned bad value
  36.  *
  37.  * Revision 30.0  1994/06/10  18:04:45  dice
  38.  * .
  39.  *
  40.  * Revision 1.5  1994/04/15  21:16:17  jtoebes
  41.  * Fixed code for dynamic stack allocations.
  42.  *
  43.  * Revision 1.4  1993/11/22  00:28:36  jtoebes
  44.  * Final cleanup to eliminate all cerror() messages with strings.
  45.  *
  46.  * Revision 1.3  1993/11/14  21:37:04  jtoebes
  47.  * FIXED BUG01140 - DC1 is misaligning structure sizes.
  48.  * Output a ds.w 0 to align strings to a word boundary.
  49.  *
  50.  *
  51. **/
  52.  
  53. #include "defs.h"
  54. #include "asm.h"
  55.  
  56. Prototype long AsmState;
  57. Prototype long LabelReturn;
  58. Prototype long LabelProfBeg;
  59. Prototype long LabelProfEnd;
  60. Prototype long LabelRegsUsed;
  61. Prototype long RegReserved;
  62. Prototype long GlobalRegReserved;
  63. Prototype char LastSectBuf[256];
  64. Prototype char *LastSectName;
  65. Prototype char *SegNames[];
  66. Prototype char *SegTypes[];
  67. Prototype short OutAlign;
  68.  
  69. char *SegNames[] = { "text", "data", "fardata", "bss", "farbss", "altdata", "altbss", "altcode", "combss", "farcombss" };
  70. char *SegTypes[] = { "code", "data", "data",    "bss", "bss"   , "data",    "bss",    "code",    "common", "common" };
  71.  
  72. long AsmState = 0;    /*  includes msb masking bits    */
  73. long  LabelStackUsed;
  74. long  LabelRegsUsed;
  75. long  LabelReturn;
  76. long  LabelRegMaskUsed;
  77. long  LabelArgsBytes;
  78. long  LabelProfBeg;
  79. long  LabelProfEnd;
  80. long  RegReserved;
  81. long  GlobalRegReserved = RF_A5|RF_A7;
  82. char  LastSectBuf[256];
  83. char *LastSectName;
  84.  
  85. short OutAlign;
  86. short OAlgnReserved;
  87.  
  88. static Stor SOff  = { ST_RelReg, RB_SP, 4 };
  89. static Stor SPush = { ST_Push, 0, 4 };
  90. static Stor SCallerBlk = { ST_RelArg, RB_FP, 4 };
  91.  
  92. Prototype void asm_extern(Var *);
  93. Prototype void asm_export(Symbol *);
  94. Prototype void asm_procbegin(Var *);
  95. Prototype void asm_regentry(Var *);
  96. Prototype void asm_proclink(Var *);
  97. Prototype void asm_procend(Var *, short);
  98. Prototype void asm_returnstorage(Exp *);
  99. Prototype void asm_dynamictag(Var *);    /* XXX */
  100. Prototype void asm_segment(Var *);
  101. Prototype void asm_align(long);
  102. Prototype void asm_ds(Symbol *, long);
  103. Prototype void asm_string(long, ubyte *, long, long, long);
  104. Prototype void asm_label(long);
  105. Prototype void asm_branch(long);
  106. Prototype void asm_condbra(short, long);
  107. Prototype long asm_push(Exp *, Type *, Stor *);
  108. Prototype void asm_push_mask(long);
  109. Prototype long asm_stackbytes(Type *);
  110. Prototype void asm_call(Exp *, Stor *, Type *, Stor *, long, short);
  111. Prototype void asm_pop(long);
  112. Prototype void asm_pop_mask(long);
  113. Prototype void asm_ext(Exp *, Stor *, Stor *, long);
  114. Prototype void asm_test(Exp *, Stor *);
  115. Prototype void asm_test_scc(Exp *, long, Stor *, short, Stor *);
  116. Prototype void asm_cond_scc(Exp *, long, Stor *, Stor *, short *, Stor *);
  117. Prototype void asm_sccb(Exp *, Stor *, short, short);
  118. Prototype void asm_clr(Exp *, Stor *);
  119. Prototype void asm_movei(Exp *, long, Stor *);
  120. Prototype void asm_neg(Exp *, Stor *, Stor *);
  121. Prototype void ThreeOp(Exp *, Stor *, Stor *, Stor *, void (*)(Exp *, Stor *, Stor *, Stor *));
  122. Prototype void asm_add(Exp *, Stor *, Stor *, Stor *);
  123. Prototype void asm_sub(Exp *, Stor *, Stor *, Stor *);
  124. Prototype void asm_xor(Exp *, Stor *, Stor *, Stor *);
  125. Prototype void asm_and(Exp *, Stor *, Stor *, Stor *);
  126. Prototype void asm_or(Exp *, Stor *, Stor *, Stor *);
  127. Prototype void asm_test_and(Exp *, Stor *, Stor *);
  128. Prototype void asm_switch(Exp *, long, long *, long *, long);
  129. Prototype long SizeFit(long);
  130. Prototype long SizeFitSU(long, Stor *);
  131. Prototype void asm_end(void);
  132. Prototype long asm_rcomove(Exp *, char *, short, Stor *);
  133. Prototype void asm_exg(Stor *, Stor *);
  134.  
  135. Prototype long RegCallOrder(Type *, char *, char *);
  136. Prototype void AutoAssignRegisteredArgs(Var **, short);
  137.  
  138. Local void asm_gen_logic_class(Exp *, char *, char *, long, Stor *, Stor *, Stor *, long);
  139. Local void SortCases(Exp *, long *, long *, long);
  140. Local void SubDivideSwitch(Exp *, Stor *, Stor *, long, long, long, long, long *, long *);
  141. Local void extop(long, long, Stor *);
  142.  
  143. void
  144. asm_extern(var)
  145. Var *var;
  146. {
  147.     if (var->var_Stor.st_Flags & SF_REGARGSUSED)
  148.     printf("\txref\t@%s\n", SymToString(var->Sym));
  149.     printf("\txref\t_%s\n", SymToString(var->Sym));
  150. }
  151.  
  152. void
  153. asm_export(sym)
  154. Symbol *sym;
  155. {
  156.     printf("\txdef\t_%s\n", SymToString(sym));
  157. }
  158.  
  159.  
  160. void
  161. asm_procbegin(var)
  162. Var *var;
  163. {
  164.     char *prefix;
  165.  
  166.     LabelStackUsed  = AllocLabel();
  167.     LabelReturn     = AllocLabel();
  168.     LabelRegsUsed   = AllocLabel();
  169.     LabelRegMaskUsed= AllocLabel();
  170.     LabelArgsBytes  = AllocLabel();
  171.  
  172.     /*
  173.      *    prefix, TF_REGCALL uses @
  174.      *        TF_STKCALL uses _
  175.      */
  176.  
  177.     if ((var->Flags & TF_REGCALL) && (var->Flags & TF_STKCALL))
  178.     {
  179.     dbprintf(("RegCall & StkCall!"));   /* XXX */
  180.     Assert(0);
  181.     }
  182.  
  183.     if (var->Flags & TF_REGCALL)
  184.     prefix = "@";
  185.     else
  186.     prefix = "_";
  187.  
  188.     /*
  189.      *    autoinit code for procedure
  190.      */
  191.  
  192.     if (var->Flags & TF_AUTOINIT) {
  193. #ifdef REGISTERED
  194.     printf("\tsection\tautoinit1,code\n");
  195.     printf("\tjsr\t_%s\n", SymToString(var->Sym));
  196.     puts(LastSectBuf);
  197. #else
  198.     yerror(var->LexIdx, EUNREG_AUTOINIT);
  199. #endif
  200.     } else if (var->Flags & TF_AUTOEXIT) {
  201. #ifdef REGISTERED
  202.     printf("\tsection\tautoexit1,code\n");
  203.     printf("\tjsr\t_%s\n", SymToString(var->Sym));
  204.     puts(LastSectBuf);
  205. #else
  206.     yerror(var->LexIdx, EUNREG_AUTOEXIT);
  207. #endif
  208.     }
  209.  
  210.     /*
  211.      *    autoinit/exit code for profiling
  212.      *
  213.      *    Use address of label(s) after call to ID the routine(s)
  214.      */
  215.  
  216.     if (ProfOpt && (var->Flags & (TF_NOPROF|TF_INTERRUPT)) == 0) {
  217.     long l1 = AllocLabel();
  218.  
  219.     LabelProfBeg = AllocLabel();
  220.     LabelProfEnd = AllocLabel();
  221.  
  222.     AddAuxSub("ProfInit");      /*  ProfInit(rtname, pcbeg, pcend)  */
  223.     AddAuxSub("ProfExec");      /*  ProfInit(rtname, pcbeg, pcend)  */
  224.     printf("\tsection\tautoinit1,code\n");
  225.     printf("\tlea\tl%ld%s,A0\n", l1, (SmallData) ? "(A4)" : "");
  226.     printf("\tjsr\t__ProfInit\n");
  227.  
  228.     printf("\tsection\tlibdata,data\n");
  229.     printf("\tds.l\t0\n");
  230.  
  231.     printf("l%ld\n", l1);
  232.     printf("\tdc.l\t0\n");      /*  next pointer    */
  233.     printf("\tdc.l\t0\n");      /*  siblings        */
  234.     printf("\tdc.l\t0\n");      /*  our parent      */
  235.     printf("\tdc.w\t%d\n", (40 + strlen(prefix) + strlen(SymToString(var->Sym)) + (1 + 3)) & ~3);   /*  size of structure   */
  236.     printf("\tdc.w\t0\n");
  237.     printf("\tdc.l\t0\n");      /*  time stamp      */
  238.     printf("\tdc.l\t0\n");      /*  accum time      */
  239.     printf("\tdc.l\t0\n");      /*  total time      */
  240.     printf("\tdc.l\t0\n");      /*  # of calls      */
  241.     printf("\tdc.l\tl%ld\n", LabelProfBeg);
  242.     printf("\tdc.l\tl%ld\n", LabelProfEnd);
  243.     printf("\tdc.b\t\'%s%s\',0\n", prefix, SymToString(var->Sym));
  244.     printf("\tds.l\t0\n");
  245.  
  246.     puts(LastSectBuf);
  247.     }
  248.  
  249.     if (GenLinkOpt || ((GenStackOpt || (var->Flags & TF_STKCHECK)) && !(var->Flags & (TF_INTERRUPT|TF_NOSTKCHECK))))
  250.     printf("\tprocstart\t0\n");     /*  enable opts except link/unlk */
  251.     else
  252.     printf("\tprocstart\n");        /*  enable optimizations */
  253.     printf("\tds.w\t0\n");              /*  Align the code       */
  254.  
  255.     if (!(var->Flags & TF_STATIC))
  256.     printf("\txdef\t%s%s\n", prefix, SymToString(var->Sym));
  257.  
  258.     printf("%s%s:\n", prefix, SymToString(var->Sym));
  259.  
  260.     if (ProfOpt && (var->Flags & (TF_NOPROF|TF_INTERRUPT)) == 0) {
  261.     printf("\tjsr\t__ProfExec%s\n", (SmallCode) ? "(pc)" : "");
  262.     printf("l%ld\n", LabelProfBeg);
  263.     }
  264.     printf("\tmovem.l\tl%ld,-(sp)\n", LabelRegMaskUsed);
  265. }
  266.  
  267. /*
  268.  *  REGCALLORDER()
  269.  *
  270.  *  Fill a register ordering array (ano) with the registers for a
  271.  *  registerized procedure call.
  272.  *
  273.  *  Returns a mask of registers that conflict with currently allocated
  274.  *  registers.    Would previously generate a conflict bit for byte sized
  275.  *  address register quantities but no longer does so (has been fixed
  276.  *  in GenRegArgs)
  277.  */
  278.  
  279. long
  280. RegCallOrder(type, ano, prgno)
  281. Type *type;
  282. char *ano;
  283. char *prgno;    /*  prefilled pragma regs or NULL   */
  284. {
  285.     short i;
  286.     Var *var;
  287.     long regMask = 0;
  288.  
  289.     for (i = 0; i < type->Args && (var = type->Vars[i]); ++i) {
  290.     short regNo = 0;
  291.  
  292.     if (prgno && prgno[i] != -1) {
  293.         regNo = prgno[i];
  294.     } else if (var->RegFlags & RF_REGISTER) {
  295.         regNo = var->RegFlags & RF_REGMASK;
  296.     } else {
  297.         dbprintf(("RegFlags %d prgno %08lx prgno[i] %d\n",
  298.             var->RegFlags,
  299.             (long)prgno,
  300.             (prgno) ? prgno[i] : -1
  301.         ));
  302.         Assert(0);
  303.     }
  304.     regMask |= RegCallUseRegister(regNo);
  305.     ano[i] = regNo;
  306. #ifdef NOTDEF
  307.     if (regNo >= RB_ADDR && var->Type->Size == 1) {
  308.         dbprintf(("; RegCallOrder ADREG/CHAR %d\n", regNo));
  309.         regMask |= 1 << regNo;
  310.     }
  311. #endif
  312.     }
  313.     if (prgno) {
  314.     short regNo;
  315.  
  316.     while (i < 16 && (regNo = prgno[i]) != -1) {
  317.         ano[i] = regNo;
  318.         regMask |= RegCallUseRegister(regNo);
  319.         ++i;
  320.     }
  321.     }
  322.     while (i < 16)
  323.     ano[i++] = -1;
  324.     return(regMask);
  325. }
  326.  
  327. /*
  328.  *  AUTOASSIGNREGISTEREDARGS()
  329.  *
  330.  *  When automatic registerized variables are enabled this routine
  331.  *  will assign procedure arguments to registers.  This routine is
  332.  *  also called for explicitly registerized procedure calls but
  333.  *  in that case the registers are already assigned and we have an
  334.  *  effective nop.
  335.  */
  336.  
  337. void
  338. AutoAssignRegisteredArgs(Var **vars, short args)
  339. {
  340.     short i;
  341.     long regMask = 0;
  342.     Var *var;
  343.  
  344.     for (i = 0; i < args && (var = vars[i]); ++i) {
  345.     Assert(i < 16);
  346.  
  347.     if ((var->RegFlags & RF_REGISTER) == 0) {
  348.         long pick = 0;
  349.  
  350.         if (var->Type->Id == TID_INT) {
  351.         if ((regMask & RF_D0) == 0)
  352.             pick = RB_D0;
  353.         else if ((regMask & RF_D1) == 0)
  354.             pick = RB_D1;
  355.         else if ((regMask & RF_A0) == 0)
  356.             pick = RB_A0;
  357.         else if ((regMask & RF_A1) == 0)
  358.             pick = RB_A1;
  359.         else
  360.             Assert(0);
  361.         } else {
  362.         if ((regMask & RF_A0) == 0)
  363.             pick = RB_A0;
  364.         else if ((regMask & RF_A1) == 0)
  365.             pick = RB_A1;
  366.         else if ((regMask & RF_D0) == 0)
  367.             pick = RB_D0;
  368.         else if ((regMask & RF_D1) == 0)
  369.             pick = RB_D1;
  370.         else
  371.             Assert(0);
  372.         }
  373.         var->RegFlags = pick | RF_REGISTER;
  374.     }
  375.     regMask |= 1 << (var->RegFlags & RF_REGMASK);
  376.     }
  377. }
  378.  
  379. /*
  380.  *  returns whether a register swap had to be done (so GEN.C can invalidate
  381.  *  the variable as reservable since it has been effectively modified)
  382.  */
  383.  
  384. long
  385. asm_rcomove(Exp *exp, char *ano, short i, Stor *d)
  386. {
  387.     Stor t;
  388.     short swap = -1;
  389.     short si;
  390.  
  391.     t.st_Flags= SF_TMP;
  392.     t.st_Type = ST_Reg;
  393.     t.st_RegNo= ano[i];
  394.     t.st_Size = d->st_Size;
  395.  
  396.     if (d->st_Type != ST_Reg) {
  397.     asm_move(exp, &t, d);
  398.     ano[i] = 0;
  399.     return(0);
  400.     }
  401.  
  402.     if (d->st_RegNo != ano[i]) {
  403.     for (si = 0; si < 16; ++si) {
  404.         if (d->st_RegNo == ano[si]) {
  405.         swap = si;
  406.         break;
  407.         }
  408.     }
  409.     if (swap < 0) {     /*    destination contents garbage    */
  410.         outop("move", 4, &t, d);
  411.     } else {        /*    destination contents precious    */
  412.         outop("exg", 4, &t, d);
  413.         ano[si] = t.st_RegNo;
  414.     }
  415.     ano[i] = -1;
  416.     }
  417.     return(swap);
  418. }
  419.  
  420. void
  421. asm_exg(s1, s2)
  422. Stor *s1;
  423. Stor *s2;
  424. {
  425.     if (SameStorage(s1, s2) == 0)
  426.     outop("exg", 4, s1, s2);
  427. }
  428.  
  429. #ifdef NOTDEF
  430. /*
  431.  *  redefine the movem label.. make the old one nil (effecively move
  432.  *  the movem to *after* the registers are loaded)
  433.  */
  434.  
  435. void
  436. asm_regentry(var)
  437. Var *var;
  438. {
  439.     char *nam = SymToString(var->Sym);
  440.  
  441.     printf("l%ld\teqr\n", LabelRegMaskUsed);
  442.     printf("\txdef\t@%s\n", nam);
  443.     printf("@%s:\n", nam);
  444.  
  445.     LabelRegMaskUsed= AllocLabel();
  446.     printf("\tmovem.l\tl%ld,-(sp)\n", LabelRegMaskUsed);
  447. }
  448. #endif
  449.  
  450. void
  451. asm_proclink(var)
  452. Var *var;
  453. {
  454.     if (var->Flags & (TF_INTERRUPT|TF_GETA4)) {
  455.     if (var->Flags & TF_GETA4) {
  456. #ifdef REGISTERED
  457.         RegReserved |= REGSDPTR;    /*  XXX remove me   */
  458.         AddAuxSub("ABSOLUTE_BAS");
  459.         if (PIOpt) {
  460.         printf("\tlea\t__ABSOLUTE_BAS(pc),A4\n"
  461.                "\tlea\t32766(A4),A4\n"
  462.               );
  463.         } else {
  464.         printf("\tlea\t__ABSOLUTE_BAS+32766,A4\n");
  465.         if (ResOpt)
  466.             yerror(var->LexIdx, EERROR_GETA4_ILLEGAL);
  467.         }
  468. #else
  469.         yerror(var->LexIdx, EUNREG_GETA4);
  470. #endif
  471.  
  472.     }
  473.     /* int code? */
  474.     }
  475.  
  476.     /*
  477.      *    If -gs is specified do stack checking, otherwise just do a simple
  478.      *    link instruction.
  479.      *
  480.      *    In order to do stack checking we have to simulate the link
  481.      *    instruction and modify A5 instead of SP, then check A6, then
  482.      *    EXG the two if we are still ok.  We cannot store the link
  483.      *    equivalent into A7 until we know it is safe.
  484.      */
  485.  
  486.     if ((GenStackOpt || (var->Flags & TF_STKCHECK)) && !(var->Flags & (TF_INTERRUPT|TF_NOSTKCHECK))) {
  487.     long l = AllocLabel();
  488.  
  489.     AddAuxSub("stk_base");
  490.     AddAuxSub("stk_alloc");
  491.  
  492.     /*
  493.      *  simulate link instruction but with A5 and A7 swapped
  494.      */
  495.     printf("\tmove.l\tA%d,-(sp)\n", RB_FP - RB_ADDR);
  496.     printf("\tlea\t-l%ld(sp),A%d\n", LabelStackUsed, RB_FP - RB_ADDR);
  497.     printf("\tcmp.l\t__stk_base%s,A%d\n",
  498.         ((SmallData) ? "(A4)" : ""),
  499.         RB_FP - RB_ADDR
  500.     );
  501.     printf("\tbhi\tl%ld\n", l);
  502.  
  503.     /*
  504.      *  Call __stk_alloc() (name changed from __stack_alloc() to avoid
  505.      *  incompatible library functions after dynamic stacks were fixed).
  506.      *  __stk_alloc() requires the number of bytes of arguments and
  507.      *  the number of bytes of saved registers in order to be able to
  508.      *  properly allocate a new stack frame and copy the appropriate
  509.      *  information.
  510.      *
  511.      *  __stk_alloc() will replace the return vector and saved frame
  512.      *  pointer in the new frame to point to __stk_free(), which
  513.      *  restores the old frame.
  514.      *
  515.      *  NOTE: The minimum argument size for K&R procedures is 256 bytes
  516.      *  more then the specified arguments in order to accomodate
  517.      *  var-args functions.  ANSI prototyped procedures are much more
  518.      *  efficient, only copying the actual number of arguments, plus
  519.      *  256 more bytes if the (, ...) form is used.
  520.      */
  521.  
  522.     {
  523.         BlockStmt *block = var->u.Block;
  524.         long argBytes = block->Frame.ArgsStackUsed;
  525.  
  526.         if (var->Flags & TF_PROTOTYPE) {
  527.         if (var->Flags & TF_DOTDOTDOT)
  528.             argBytes += 256;
  529.         } else {
  530.         argBytes += 256;
  531.         }
  532.         if (argBytes < 32768)
  533.         printf("\tpea\t%ld.W\n", argBytes);
  534.         else
  535.         printf("\tpea\t%ld\n", argBytes);
  536.     }
  537.     printf("\tpea\tl%ld-8.W\n", LabelRegsUsed);
  538.     printf("\tjsr\t__stk_alloc%s\n", (SmallCode) ? "(pc)" : "");
  539.  
  540.     /*
  541.      *  exg A5, A7 to 'make it right'
  542.      */
  543.     printf("l%ld\texg\tsp,A%d\n", l, RB_FP - RB_ADDR);
  544.     } else {
  545.     printf("\tlink\tA%d,#-l%ld\n", RB_FP - RB_ADDR, LabelStackUsed);
  546.     }
  547. }
  548.  
  549. void
  550. asm_procend(Var *var, short forceLink)
  551. {
  552.     BlockStmt *block = var->u.Block;
  553.     short count;
  554.     short dummy;
  555. #ifdef MINIDICE
  556.     static short Cntr = (MINIMAXPROCS + 2) * 3;
  557. #endif
  558.  
  559.     long stack = Align(block->Frame.DownStackUsed + block->Frame.StackUsed, STACK_ALIGN);
  560.     long mask = GetUsedRegisters() & ~RegReserved;
  561.  
  562.     if (var->Flags & (TF_INTERRUPT)) {
  563.     if (SmallData != 2)
  564.         mask |= REGSDPTR;
  565.     if (block->Frame.Flags & FF_CALLMADE)
  566.         mask |= REGSCRATCH;
  567.     } else {
  568.     mask &= ~REGSCRATCH;
  569.     }
  570.     if (var->Flags & TF_GETA4)
  571.     mask |= REGSDPTR;
  572.  
  573. #ifdef MINIDICE
  574.     else
  575.         Cntr -= 3;
  576. #endif
  577.  
  578.     if (stack > 32767)
  579.     yerror(var->LexIdx, EERROR_TOO_MANY_AUTOS);
  580.  
  581. #ifdef MINIDICE
  582.     if (Cntr <= 0) {
  583.         GlobalRegReserved |= 1 << (var->LexIdx & 31);
  584.         dbprintf(("Holy shit batman!  I've been compromised %d\n", (var->LexIdx & 31)));
  585.     }
  586. #endif
  587.  
  588.     /*
  589.      *    return, unlk, restore regs, rts.
  590.      */
  591.  
  592.     asm_label(LabelReturn);
  593.     printf("\tunlk\tA%d\n", RB_FP - RB_ADDR);
  594.     count = asm_restore_regs(mask);
  595.  
  596.     if (var->Flags & TF_INTERRUPT) {
  597.     printf("\trte\n");
  598.     } else {
  599.     if (ProfOpt && (var->Flags & TF_NOPROF) == 0) {
  600.         printf("\tjsr\t__ProfExec%s\n", (SmallCode) ? "(pc)" : "");
  601.         printf("l%ld\n", LabelProfEnd);
  602.     }
  603.     printf("\trts\n");
  604.     }
  605.  
  606.     printf("l%ld\treg\t%s\n", LabelRegMaskUsed, RegMaskToString(mask, &dummy));
  607.     printf("l%ld\tequ\t%d\n", LabelRegsUsed, 8 + count * 4);
  608.     printf("l%ld\tequ\t%ld\n", LabelStackUsed, stack);
  609.     printf("\tprocend");
  610.     if (forceLink)
  611.     printf(" forcelink");
  612.     puts("");
  613. }
  614.  
  615. void
  616. asm_push_mask(mask)
  617. long mask;
  618. {
  619.     if (mask) {
  620.     short n;
  621.     char *ptr = RegMaskToString(mask, &n);
  622.  
  623.     printf("\tmove%s.l\t%s,-(sp)\n", ((n > 1) ? "m" : ""), ptr);
  624.     }
  625. }
  626.  
  627. void
  628. asm_pop_mask(mask)
  629. long mask;
  630. {
  631.     if (mask) {
  632.     short n;
  633.     char *ptr = RegMaskToString(mask, &n);
  634.  
  635.     printf("\tmove%s.l\t(sp)+,%s\n", ((n > 1) ? "m" : ""), ptr);
  636.     }
  637. }
  638.  
  639. void
  640. asm_returnstorage(exp)
  641. Exp *exp;
  642. {
  643.     Stor sd0;
  644.     Stor sd1;
  645.     Stor sa0;
  646.     Stor sa1;
  647.     Stor *s = &exp->ex_Stor;
  648.  
  649.     switch(exp->ex_Type->Id) {
  650.     case TID_STRUCT:
  651.     case TID_UNION:
  652.     {
  653.         int label = AllocLabel();
  654.  
  655.         /*
  656.          *    structures and unions are returned to storage allocated by
  657.          *    the caller.  The caller passes a pointer to this storage
  658.          *    as the first argument in the call, which is -4 relative
  659.          *    ST_RelArg/fp (asubs.c will modify the basic RelArg offset
  660.          *    so 0 always points to the first user arguments)
  661.          *
  662.          *    Note that if the caller expects no return data it will
  663.          *    pass NULL for the pointer, in which case we do NOT
  664.          *    copy the return structure.
  665.          */
  666.  
  667.         /*
  668.          *    used to allocate A0 but this is illegal -- A0 might already
  669.          *    be used to hold the source of the copy.
  670.          */
  671.  
  672.         AllocAddrRegister(&sa0);
  673.         SCallerBlk.st_Offset = -4;
  674.         asm_move(exp, &SCallerBlk, &sa0);
  675.  
  676.         asm_test(exp, &sa0);
  677.         asm_condbra(COND_EQ, label);
  678.  
  679.         sa0.st_Offset = 0;
  680.         sa0.st_Type = ST_RelReg;
  681.         sa0.st_Size = s->st_Size;
  682.         asm_move(exp, s, &sa0);
  683.         FreeRegister(&sa0);
  684.         asm_label(label);
  685.     }
  686.     break;
  687.     case TID_FLT:
  688.     AllocDataRegisterAbs(&sd0, 4, RB_D0);
  689.     AllocDataRegisterAbs(&sd1, 4, RB_D1);
  690.  
  691.     if (s->st_Type == ST_FltConst) {
  692.         ulong ary[4];
  693.  
  694.         asm_fltconst(exp, s, ary);
  695.  
  696.         switch(s->st_Size) {
  697.         case 16:
  698.         AllocAddrRegisterAbs(&sa0, RB_A0);
  699.         AllocAddrRegisterAbs(&sa1, RB_A1);
  700.         asm_movei(exp, ary[3], &sa1);
  701.         asm_movei(exp, ary[2], &sa0);
  702.         FreeRegister(&sa0);
  703.         FreeRegister(&sa1);
  704.         case 8:
  705.         asm_movei(exp, ary[1], &sd1);
  706.         case 4:
  707.         asm_movei(exp, ary[0], &sd0);
  708.         break;
  709.         default:
  710.         Assert(0);
  711.         }
  712.     } else {
  713.         char *sstr = StorToString(s, NULL);
  714.  
  715.         switch(s->st_Size) {
  716.         case 4:
  717.         printf("\tmove.l\t%s,D0\n", sstr);
  718.         break;
  719.         case 8:
  720.         printf("\tmovem.l\t%s,D0/D1\n", sstr);
  721.         break;
  722.         case 16:
  723.         AllocAddrRegisterAbs(&sa0, RB_A0);
  724.         AllocAddrRegisterAbs(&sa1, RB_A1);
  725.         printf("\tmovem.l\t%s,D0/D1/A0/A1\n", sstr);
  726.         FreeRegister(&sa0);
  727.         FreeRegister(&sa1);
  728.         break;
  729.         default:
  730.         Assert(0);
  731.         }
  732.     }
  733.     FreeRegister(&sd0);
  734.     FreeRegister(&sd1);
  735.     break;
  736.     case TID_INT:        /*  size 4  D0        */
  737.     case TID_PTR:
  738.     Assert(s->st_Size == 4);
  739.     AllocDataRegisterAbs(&sd0, 4, RB_D0);
  740.     asm_move(exp, s, &sd0);
  741.     FreeRegister(&sd0);
  742.     break;
  743.     default:
  744.     yerror(exp->ex_LexIdx, EERROR_UNSUPPORTED_RETURN_TYPE);
  745.     break;
  746.     }
  747. }
  748.  
  749. #ifdef DYNAMIC
  750. /*
  751.  *  geneate dynamic tag code, variable is a pointer to the procedure
  752.  *  or variable we dynamically link in run-time.
  753.  *
  754.  *  procedure:    _GetHyperFunc("routine", "_stk_")
  755.  *  variable:    _GetHyperVar("variable")
  756.  *
  757.  */
  758.  
  759. void
  760. asm_dynamictag(var)
  761. Var *var;
  762. {
  763.     long l1 = AllocLabel();
  764.     long l2 = AllocLabel();
  765.     long l3 = AllocLabel();
  766.     short isVar = (var->Type->SubType->Id != TID_PROC);
  767.  
  768.     /*
  769.      *    autoinit code
  770.      */
  771.  
  772.     printf("\tsection\tautoinit1,code\n");
  773.     printf("\txref\t__AutoFail1\n");
  774.     printf("\txref\t@_%s\n",
  775.     ((isVar) ? "GetHyperVar" : "GetHyperFunc")
  776.     );
  777.     if (isVar == 0)
  778.     printf("\tlea\tl%d(pc),A1\n", l2);
  779.     printf("\tlea\tl%d(pc),A0\n", l1);
  780.     printf("\tjsr\t@_%s%s\n",
  781.     ((isVar) ? "GetHyperVar" : "GetHyperFunc"),
  782.     ((PIOpt) ? "(pc)" : "")
  783.     );
  784.     printf("\tmove.l\tD0,_%s%s\n",
  785.     SymToString(var->Sym),
  786.     ((SmallData) ? "(A4)" : "")
  787.     );
  788.     printf("\tbeq\t__AutoFail1\n");
  789.     printf("\tbra\tl%d\n", l3);
  790.     printf("l%d\tdc.b\t'_%s',0\n", l1, SymToString(var->Sym));
  791.     if (isVar == 0)
  792.     printf("l%d\tdc.b\t'_stk_',0\n", l2);
  793.     printf("\tds.w\t0\n");
  794.     printf("l%d\n", l3);
  795.  
  796.     /*
  797.      *    autoexit code to release dynamically referenced variable or routine
  798.      */
  799.  
  800.     printf("\tsection\tautoexit1,code\n");
  801.     printf("\txref\t@_%s\n",
  802.     ((isVar) ? "RelsHyperVar" : "RelsHyperFunc")
  803.     );
  804.     printf("\tmove.l\t_%s%s,A0\n",
  805.     SymToString(var->Sym),
  806.     ((SmallData) ? "(A4)" : "")
  807.     );
  808.     printf("\tjsr\t@_%s%s\n",
  809.     ((isVar) ? "RelsHyperVar" : "RelsHyperFunc"),
  810.     ((PIOpt) ? "(pc)" : "")
  811.     );
  812.  
  813.     puts(LastSectBuf);
  814. }
  815. #endif
  816.  
  817. void
  818. asm_segment(var)
  819. Var *var;
  820. {
  821.     long mask;
  822.     long state;
  823.     char *segName;
  824.     char *segType;
  825.     char *sn;
  826.  
  827. #ifdef REGISTERED
  828.     if (var->Flags & TF_CHIP)
  829.     mask = 0x40000000;
  830.     else
  831.     mask = 0;
  832. #else
  833.     mask = 0;
  834.     if (var->Flags & TF_CHIP)
  835.     yerror(var->LexIdx, EUNREG_CHIP);
  836. #endif
  837.  
  838.     if (var->var_Stor.st_Flags & SF_CODE) {
  839.     if (var->Flags & TF_AUTOINIT) {     /*    __autoinit const only    */
  840.         segName = SegNames[7];
  841.         segType = SegTypes[7];
  842.     } else {
  843.         segName = SegNames[0];
  844.         segType = SegTypes[0];
  845.     }
  846.     state = ASM_CODE;
  847.     } else {
  848.     long idx;
  849.  
  850.     if (var->u.AssExp)
  851.         state = ASM_DATA;
  852.     else
  853.         state = ASM_BSS;
  854.  
  855.     if (var->Flags & TF_AUTOINIT) {
  856.         if (var->u.AssExp)
  857.         idx = 5;
  858.         else
  859.         idx = 6;
  860.     } else if ((var->Flags & TF_FAR) || (SmallData == 0 && !(var->Flags & TF_NEAR))) {
  861.         if (var->u.AssExp)
  862.         idx = 2;
  863.         else if (UnixCommonOpt && (var->Flags & TF_STATIC) == 0)
  864.         idx = 9;
  865.         else
  866.         idx = 4;
  867.     } else {
  868.         if (var->u.AssExp)
  869.         idx = 1;
  870.         else if (UnixCommonOpt && (var->Flags & TF_STATIC) == 0)
  871.         idx = 8;
  872.         else
  873.         idx = 3;
  874.     }
  875.  
  876.  
  877.     segName = SegNames[idx];
  878.     segType = SegTypes[idx];
  879.     }
  880.     state |= mask;
  881.  
  882.     sn = LastSectBuf;
  883.  
  884.     if (AsmState != state || LastSectName != segName) {
  885.     if (mask)
  886.         sprintf(sn, "\tsection %s,%s,$%08lx\n", segName, segType, mask);
  887.     else
  888.         sprintf(sn, "\tsection %s,%s\n", segName, segType);
  889.     puts(sn);
  890.     AsmState = state;
  891.     LastSectName = segName;
  892.     OutAlign = 1;
  893.     }
  894. }
  895.  
  896. void
  897. asm_align(long size)
  898. {
  899.     switch(size) {
  900.     case 1:
  901.     break;
  902.     case 2:
  903.     if (OutAlign & 1)
  904.         printf("\tds.w 0\n");
  905.     OutAlign = 2;
  906.     break;
  907.     case 4:
  908.     default:
  909.     if (OutAlign & 3)
  910.         printf("\tds.l 0\n");
  911.     OutAlign = 4;
  912.     break;
  913.     }
  914. }
  915.  
  916. /*
  917.  *  Generate a string ref.  An internationalizable reference generates a
  918.  *  table reference (and the string is forced to be in a code section elsewhere
  919.  *  in the code)
  920.  */
  921.  
  922. void
  923. asm_string(label, str, bytes, flags, iidx)
  924. long label;
  925. ubyte *str;
  926. long bytes;
  927. long flags;
  928. long iidx;
  929. {
  930.     short i = 0;
  931.     char buf[128];
  932.     char *p = buf;
  933.  
  934. #ifdef COMMERCIAL
  935.     if (iidx >= 0) {
  936.     long newLabel = AllocLabel();
  937.  
  938.     printf("\tsection\tilocale,data\n");
  939.     printf("l%ld\tdc.l\tl%ld,%ld\n", label, newLabel, iidx);
  940.     puts(LastSectBuf);
  941.     label = newLabel;
  942.     }
  943. #endif
  944.  
  945.     if (flags & (TF_CONST | TF_SHARED))
  946.     asm_segment(&DummyCodeVar);
  947.     else
  948.     asm_segment(&DummyDataVar);
  949.  
  950.     printf("\tds.w\t0\n");  /* Word align the string */
  951.  
  952.     *p++ = 'l';
  953.     p = itodec(p, label);
  954.     *p++ = '\n';
  955.  
  956.     while (bytes--) {
  957.     if (i) {
  958.         *p++ = ',';
  959.     } else {
  960.         strcpy(p, "\n\tdc.b\t");
  961.         p += 7;
  962.     }
  963.     *p++ = '$';
  964.     p = itohex(p, *str++);
  965.     if (++i == 12) {
  966.         fwrite(buf, p - buf, 1, stdout);
  967.         p = buf;
  968.         i = 0;
  969.     }
  970.     }
  971.     *p++ = '\n';
  972.     fwrite(buf, p - buf, 1, stdout);
  973. }
  974.  
  975. void
  976. asm_label(label)
  977. long label;
  978. {
  979.     char buf[32];
  980.     char *ptr;
  981.  
  982.     buf[0] = 'l';
  983.     ptr = itodec(buf + 1, label);
  984.     *ptr = '\n';
  985.     ++ptr;
  986.     fwrite(buf, 1, ptr - buf, stdout);
  987. }
  988.  
  989. /*
  990.  *  BRANCHING.    NOTE NOTE NOTE.  Whenever we branch we must check
  991.  *  for forced registers which must be restored.
  992.  */
  993.  
  994. void
  995. asm_branch(label)
  996. long label;
  997. {
  998.     printf("\tbra\tl%ld\n", label);
  999. }
  1000.  
  1001. void
  1002. asm_condbra(short cond, long label)
  1003. {
  1004.     char *str = "bad";
  1005.  
  1006.     switch(cond) {
  1007.     case COND_LT:
  1008.     str = "blt";
  1009.     break;
  1010.     case COND_LTEQ:
  1011.     str = "ble";
  1012.     break;
  1013.     case COND_GT:
  1014.     str = "bgt";
  1015.     break;
  1016.     case COND_GTEQ:
  1017.     str = "bge";
  1018.     break;
  1019.     case COND_EQ:
  1020.     str = "beq";
  1021.     break;
  1022.     case COND_NEQ:
  1023.     str = "bne";
  1024.     break;
  1025.     case CF_UNS|COND_LT:
  1026.     str = "bcs";
  1027.     break;
  1028.     case CF_UNS|COND_LTEQ:
  1029.     str = "bls";
  1030.     break;
  1031.     case CF_UNS|COND_GT:
  1032.     str = "bhi";
  1033.     break;
  1034.     case CF_UNS|COND_GTEQ:
  1035.     str = "bcc";
  1036.     break;
  1037.     case CF_UNS|COND_EQ:
  1038.     str = "beq";
  1039.     break;
  1040.     case CF_UNS|COND_NEQ:
  1041.     str = "bne";
  1042.     break;
  1043.  
  1044.     case -COND_LT:
  1045.     str = "bge";
  1046.     break;
  1047.     case -COND_LTEQ:
  1048.     str = "bgt";
  1049.     break;
  1050.     case -COND_GT:
  1051.     str = "ble";
  1052.     break;
  1053.     case -COND_GTEQ:
  1054.     str = "blt";
  1055.     break;
  1056.     case -COND_EQ:
  1057.     str = "bne";
  1058.     break;
  1059.     case -COND_NEQ:
  1060.     str = "beq";
  1061.     break;
  1062.     case -(CF_UNS|COND_LT):
  1063.     str = "bcc";
  1064.     break;
  1065.     case -(CF_UNS|COND_LTEQ):
  1066.     str = "bhi";
  1067.     break;
  1068.     case -(CF_UNS|COND_GT):
  1069.     str = "bls";
  1070.     break;
  1071.     case -(CF_UNS|COND_GTEQ):
  1072.     str = "bcs";
  1073.     break;
  1074.     case -(CF_UNS|COND_EQ):
  1075.     str = "bne";
  1076.     break;
  1077.     case -(CF_UNS|COND_NEQ):
  1078.     str = "beq";
  1079.     break;
  1080.     case COND_BPL:
  1081.     str = "bpl";
  1082.     break;
  1083.     case COND_BMI:
  1084.     str = "bmi";
  1085.     break;
  1086.     default:
  1087.     dbprintf(("Unknown cond %d\n", cond));
  1088.     Assert(0);
  1089.     break;
  1090.     }
  1091.     printf("\t%s\tl%ld\n", str, label);
  1092. }
  1093.  
  1094.  
  1095. /*
  1096.  *  push args onto stack, return bytes pushed.
  1097.  */
  1098.  
  1099. long
  1100. asm_push(exp, type, s)
  1101. Exp *exp;
  1102. Type *type;
  1103. Stor *s;
  1104. {
  1105.     Stor t;
  1106.  
  1107.     if (s->st_Type == ST_IntConst) {
  1108.     if (s->st_IntConst >= -32768 && s->st_IntConst < 32768) {
  1109.         if (s->st_IntConst == 0)
  1110.         printf("\tclr.l\t-(sp)\n");
  1111.         else
  1112.         printf("\tpea\t%ld.W\n", s->st_IntConst);
  1113.     } else {
  1114.         outop("move", 4, s, &SPush);
  1115.     }
  1116.     return(4);
  1117.     }
  1118.  
  1119.     if (s->st_Type == ST_FltConst) {
  1120.     long fval[4];
  1121.     short i;
  1122.  
  1123.     asm_fltconst(exp, s, fval);
  1124.     for (i = (s->st_Size >> 2) - 1; i >= 0; --i) {
  1125.         long v = fval[i];
  1126.         if (v >= -32768 && v < 32768)
  1127.         printf("\tpea\t$%08lx.W\n", v);
  1128.         else
  1129.         printf("\tpea\t$%08lx\n", v);
  1130.     }
  1131.     return(s->st_Size);
  1132.     }
  1133.  
  1134.     /*
  1135.      *    note, IntConst case already handled.
  1136.      */
  1137.  
  1138.     if (type->Id == TID_ARY || type->Id == TID_PROC || (s->st_Flags & SF_LEA)) {
  1139.     outop("pea", 4, NULL, s);
  1140.     return(4);
  1141.     }
  1142.  
  1143.     /*
  1144.      *    pointer, long, 4 byte structure
  1145.      */
  1146.  
  1147.     if (s->st_Size == 4) {
  1148.     outop("move", 4, s, &SPush);
  1149.     return(4);
  1150.     }
  1151.  
  1152.     /*
  1153.      *    structure or fp number, guarenteed to be word aligned.    Push
  1154.      *    exact size.
  1155.      */
  1156.  
  1157.     if (type->Id != TID_INT) {
  1158.     long bytes = s->st_Size;
  1159.  
  1160.     if (s->st_Size < 4) {
  1161.         outop("move", s->st_Size, s, &SPush);
  1162.         return(s->st_Size);
  1163.     }
  1164.     if ((s->st_Type < ST_RelReg || s->st_Type > ST_RegIndex) && s->st_Type != ST_PtrConst)
  1165.     {
  1166.         dbprintf(("bad type in asm_push: %d\n", s->st_Type));
  1167.         Assert(0);
  1168.     }
  1169.  
  1170.     if (bytes <= LGBO_SIZE && s->st_Offset >= -32768 + LGBO_SIZE && s->st_Offset < 32767 - LGBO_SIZE) {
  1171.         long oldOffset = s->st_Offset;
  1172.  
  1173.         s->st_Offset += bytes;
  1174.         while (bytes >= 4) {
  1175.         bytes -= 4;
  1176.         s->st_Offset -= 4;
  1177.         outop("move", 4, s, &SPush);
  1178.         }
  1179.         s->st_Offset = oldOffset;
  1180.         if (bytes)
  1181.         outop("move", bytes, s, &SPush);
  1182.     } else {
  1183.         long label = AllocLabel();
  1184.         Stor a;
  1185.  
  1186.         if (bytes & 1)
  1187.         yerror(exp->ex_LexIdx, EERROR_PASS_UNALIGNED_STRUCT);
  1188.  
  1189.         LockStorage(s);
  1190.         AllocDataRegister(&t, 4);
  1191.         AllocAddrRegister(&a);
  1192.         asm_lea(exp, s, bytes, &a);     /*  end of struct   */
  1193.         asm_movei(exp, bytes >> 2, &t);    /*  # of longwords  */
  1194.         if (bytes & 2)
  1195.         printf("\tmove.w\t-(A%c),-(sp)\n", a.st_RegNo - RB_ADDR + '0');
  1196.         asm_label(label);
  1197.         printf("\tmove.l\t-(A%c),-(sp)\n", a.st_RegNo - RB_ADDR + '0');
  1198.         printf("\tsubq.l\t#1,%s\n", StorToString(&t, NULL));
  1199.         asm_condbra(COND_NEQ, label);
  1200.  
  1201.         FreeRegister(&t);
  1202.         FreeRegister(&a);
  1203.         UnlockStorage(s);
  1204.     }
  1205.     return(s->st_Size);
  1206.     }
  1207.  
  1208.     /*
  1209.      *    < sizeof(int), optimizeo.  push an entire longword quantity even if
  1210.      *    the upper bits would be garbage.
  1211.      */
  1212.  
  1213.     Assert(s->st_Size < 4);
  1214.  
  1215.     if (s->st_Type == ST_Reg) {
  1216.     outop("move", 4, s, &SPush);
  1217.     return(4);
  1218.     }
  1219.  
  1220.     /*
  1221.      *    safe to push extranious garbage (assuming offset lw aligned)
  1222.      */
  1223.  
  1224.     if (s->st_Type == ST_RelArg || (s->st_RegNo == RB_FP && s->st_Type == ST_RelReg)) {
  1225.     long offset = s->st_Offset + s->st_Size - 4;
  1226.     if ((offset & 1) == 0) {
  1227.         s->st_Offset = offset;
  1228.         outop("move", 4, s, &SPush);
  1229.         s->st_Offset -= s->st_Size - 4;
  1230.         return(4);
  1231.     }
  1232.     }
  1233.  
  1234.     /*
  1235.      *    note safe to push extranious garbage from before lvalue
  1236.      */
  1237.  
  1238.     switch(s->st_Size) {
  1239.     case 1:
  1240.     printf("\tsubq.l\t#4,sp\n");
  1241.     SOff.st_Offset = 3;
  1242.     outop("move", 1, s, &SOff);
  1243.     break;
  1244.     case 2:
  1245.     outop("move", 2, s, &SPush);
  1246.     printf("\tsubq.l\t#2,sp\n");
  1247.     break;
  1248.     default:
  1249.     dbprintf(("unexpected push size %ld\n", s->st_Size));
  1250.     Assert(0);
  1251.     }
  1252.     return(4);
  1253. }
  1254.  
  1255. /*
  1256.  *  call s placing the return value into d.  d can be NULL
  1257.  *
  1258.  *  Note that d might also have been part of the registers saved,
  1259.  *  so we have to restore before moving the result.  Except D0 might
  1260.  *  have been part of the registers saved as well so in this special
  1261.  *  case we must move D0 into a temporary register before restoring.
  1262.  */
  1263.  
  1264. long
  1265. asm_stackbytes(rtype)
  1266. Type *rtype;
  1267. {
  1268.     long rtbytes = Align(rtype->Size, STACK_ALIGN);
  1269.  
  1270.     if (rtbytes > 0 && rtbytes < 4)
  1271.     rtbytes = 4;
  1272.     return(rtbytes);
  1273. }
  1274.  
  1275. /*
  1276.  *  asm_call()    make subroutine call
  1277.  *
  1278.  *  autopush:    0x01    push result back onto stack
  1279.  *        0x02    regargs call
  1280.  *
  1281.  *  note that autopush & 1 is never set for structural return types
  1282.  */
  1283.  
  1284. void
  1285. asm_call(Exp *exp, Stor *s, Type *rtype, Stor *d, long bytes, short autopush)
  1286. {
  1287.     long rtbytes;
  1288.  
  1289.     if (rtype->Id == TID_STRUCT || rtype->Id == TID_UNION) {
  1290.     Stor t;
  1291.  
  1292.     if (d) {
  1293.         asm_getlea(exp, d, &t);
  1294.         asm_push(exp, &VoidPtrType, &t);
  1295.         FreeStorage(&t);
  1296.     } else {
  1297.         AllocConstStor(&t, 0, &LongType);
  1298.         asm_push(exp, &VoidPtrType, &t);
  1299.     }
  1300.     bytes += 4;
  1301.     }
  1302.  
  1303.     outop("jsr", -1, NULL, s);
  1304.  
  1305.     if (autopush & 1) {
  1306.     char *spnam;
  1307.  
  1308.     rtbytes = asm_stackbytes(rtype);
  1309.  
  1310.     if (bytes == rtbytes) {
  1311.         spnam = "(sp)";
  1312.     } else {
  1313.         spnam = "-(sp)";
  1314.         asm_pop(bytes);
  1315.     }
  1316.  
  1317.     switch(rtbytes) {
  1318.     case 4:
  1319.         printf("\tmove.l\tD0,");
  1320.         break;
  1321.     case 8:
  1322.         printf("\tmovem.l\tD0/D1,");
  1323.         break;
  1324.     case 16:
  1325.         printf("\tmovem.l\tD0/D1/A0/A1,");
  1326.         break;
  1327.     default:
  1328.         yerror(exp->ex_LexIdx, EERROR_UNSUPPORTED_RETURN_TYPE);
  1329.         break;
  1330.     }
  1331.     puts(spnam);
  1332.     } else {
  1333.     asm_pop(bytes);
  1334.     }
  1335.  
  1336.     if (d) {
  1337.     Stor sd0;
  1338.     Stor sd1;
  1339.     Stor sa0;   /*    long double D0/D1/A0/A1  */
  1340.     Stor sa1;
  1341.  
  1342.     switch(rtype->Id) {
  1343.     case TID_STRUCT:
  1344.     case TID_UNION:
  1345.         /*
  1346.          *    structural return storage is written directly to the
  1347.          *    destination by the caller, so we need do nothing more.
  1348.          */
  1349.         break;
  1350.     case TID_FLT:
  1351.         if (d->st_Size > 4) {
  1352.         AllocDataRegisterAbs(&sd0, d->st_Size, RB_D0);
  1353.         AllocDataRegisterAbs(&sd1, d->st_Size, RB_D1);
  1354.  
  1355.         switch(d->st_Size) {
  1356.         case 8:
  1357.             printf("\tmovem.l\tD0/D1,%s\n", StorToString(d, NULL));
  1358.             break;
  1359.         case 16:
  1360.             AllocAddrRegisterAbs(&sa0, RB_A0);
  1361.             AllocAddrRegisterAbs(&sa1, RB_A1);
  1362.             printf("\tmovem.l\tD0/D1/A0/A1,%s\n", StorToString(d, NULL));
  1363.             FreeRegister(&sa0);
  1364.             FreeRegister(&sa1);
  1365.             break;
  1366.         default:
  1367.             Assert(0);
  1368.         }
  1369.  
  1370.         FreeRegister(&sd0);
  1371.         FreeRegister(&sd1);
  1372.         break;
  1373.         }
  1374.         /* fall through single prec fp  */
  1375.     case TID_INT:
  1376.     case TID_PTR:
  1377.         AllocDataRegisterAbs(&sd0, d->st_Size, RB_D0);
  1378.         asm_move(exp, &sd0, d);
  1379.         FreeRegister(&sd0);
  1380.         break;
  1381.     default:
  1382.         yerror(exp->ex_LexIdx, EERROR_UNSUPPORTED_RETURN_TYPE);
  1383.         break;
  1384.     }
  1385.     }
  1386. }
  1387.  
  1388. void
  1389. asm_pop(n)
  1390. long n;
  1391. {
  1392.     if (n) {
  1393.     if (n <= 8) {
  1394.         printf("\taddq.l\t#%ld,sp\n", n);
  1395.         return;
  1396.     }
  1397.     if (n < 32768) {
  1398.         printf("\tlea\t%ld(sp),sp\n", n);
  1399.         return;
  1400.     }
  1401.     printf("\taddi.l\t#%ld,sp\n", n);
  1402.     }
  1403. }
  1404.  
  1405. /*
  1406.  *  signed/unsigned extend w/ major optimizeo.    Also handles truncation
  1407.  *
  1408.  *  NOTE: case with data register as destination assumed never to
  1409.  *  allocate temporary registers (by asm_div, because we use D0/D1
  1410.  *  without allocating them).
  1411.  */
  1412.  
  1413. void
  1414. asm_ext(exp, s, d, sflags)
  1415. Exp *exp;
  1416. Stor *s, *d;
  1417. long sflags;
  1418. {
  1419.     Stor stor;
  1420.     Stor stor2;
  1421.     long saveDSize = d->st_Size;
  1422.  
  1423.     sflags &= SF_UNSIGNED;
  1424.     if (s->st_Type == ST_IntConst) {
  1425.     long v = s->st_IntConst;
  1426.     if (d->st_Size == 2)
  1427.         v &= 0xFFFF;
  1428.     if (d->st_Size == 1)
  1429.         v &= 0xFF;
  1430.     asm_movei(exp, v, d);
  1431.     return;
  1432.     }
  1433.  
  1434.     /*
  1435.      *    If source is an address register cannot use .b size.  Must move into
  1436.      *    data register.    However, if destination is .b sized and also a
  1437.      *    register, we can simply move it to the destination and be done
  1438.      *    with it.
  1439.      */
  1440.  
  1441.     if (d->st_Size == 1 && s->st_Type == ST_Reg && s->st_RegNo >= RB_ADDR) {
  1442.  
  1443.     /*
  1444.      *  If register-register we don't care if we use more of the
  1445.      *  destination register and this saves having to move the
  1446.      *  address register into a temporary
  1447.      */
  1448.  
  1449.     if (d->st_Type == ST_Reg) {
  1450.         long saveSSize = s->st_Size;
  1451.  
  1452.         d->st_Size = s->st_Size = 2;
  1453.         asm_move(exp, s, d);
  1454.         s->st_Size = saveSSize;
  1455.         d->st_Size = saveDSize;
  1456.         return;
  1457.     }
  1458.  
  1459.     /*
  1460.      *  s is an address register, destination size is 1.  Use .w move
  1461.      *  since can't use .b move.  Since the destination is not a
  1462.      *  register we have to allocate one.
  1463.      */
  1464.  
  1465.     AllocDataRegister(&stor2, 2);
  1466.     s->st_Size = 2;
  1467.     asm_move(exp, s, &stor2);
  1468.     s->st_Size = 1;
  1469.     stor2.st_Size = 1;
  1470.     FreeRegister(&stor2);
  1471.     s = &stor2;
  1472.     }
  1473.  
  1474.     /*
  1475.      *    If destination is address register cannot use .b size.    Easy
  1476.      *    fix is to temporarily force destination size to 2.
  1477.      */
  1478.  
  1479.     if (d->st_Size == 1 && d->st_Type == ST_Reg && d->st_RegNo >= RB_ADDR)
  1480.     d->st_Size = 2;
  1481.  
  1482.     if (s->st_Size > d->st_Size) {
  1483.  
  1484.     stor = *s;
  1485.  
  1486.     switch(stor.st_Type) {
  1487.     case ST_PtrConst:
  1488.     case ST_RelArg:
  1489.     case ST_RelReg:
  1490.     case ST_RegIndex:
  1491.     case ST_RelLabel:
  1492.     case ST_RelName:
  1493.         stor.st_Offset += s->st_Size - d->st_Size;
  1494.         break;
  1495.     }
  1496.     stor.st_Size = d->st_Size;
  1497.     asm_move(exp, &stor, d);
  1498.     } else if (s->st_Size == d->st_Size) {
  1499.     asm_move(exp, s, d);
  1500.     } else if (SameStorage(s, d) && s->st_Type == ST_Reg) {
  1501.     if (s->st_RegNo >= RB_ADDR)
  1502.     {
  1503.         dbprintf(("asm_ext : ext An"));  /*  An  */
  1504.         Assert(0);
  1505.     }
  1506.     if (sflags) {
  1507.         AllocConstStor(&stor, (1 << 8*s->st_Size) - 1, &LongType);
  1508.         stor.st_Size = d->st_Size;
  1509.         outop("andi", d->st_Size, &stor, d);
  1510.     } else {
  1511.         extop(s->st_Size, d->st_Size, d);
  1512.     }
  1513.     } else if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR && !SameRegister(s, d)) {
  1514.     if (sflags) {
  1515.         long size = d->st_Size;
  1516.  
  1517.         LockStorage(s);
  1518.         asm_movei(exp, 0, d);
  1519.         UnlockStorage(s);
  1520.         d->st_Size = s->st_Size;
  1521.         asm_move(exp, s, d);
  1522.         d->st_Size = size;
  1523.     } else {
  1524.         long size = d->st_Size;
  1525.         d->st_Size = s->st_Size;
  1526.         asm_move(exp, s, d);
  1527.         d->st_Size = size;
  1528.         extop(s->st_Size, d->st_Size, d);
  1529.     }
  1530.     } else {
  1531.     if (sflags) {
  1532.         LockStorage(s);
  1533.         AllocDataRegister(&stor, 4);
  1534.         asm_movei(exp, 0, &stor);
  1535.         UnlockStorage(s);
  1536.         stor.st_Size = s->st_Size;
  1537.         asm_move(exp, s, &stor);
  1538.         stor.st_Size = d->st_Size;
  1539.         asm_move(exp, &stor, d);
  1540.         FreeRegister(&stor);
  1541.     } else {
  1542.         AllocDataRegister(&stor, s->st_Size);
  1543.         asm_move(exp, s, &stor);
  1544.         stor.st_Size = d->st_Size;
  1545.  
  1546.         extop(s->st_Size, d->st_Size, &stor);
  1547.         asm_move(exp, &stor, d);
  1548.         FreeRegister(&stor);
  1549.     }
  1550.     }
  1551.     d->st_Size = saveDSize;
  1552. }
  1553.  
  1554. void
  1555. extop(size1, size2, d)
  1556. long size1;
  1557. long size2;
  1558. Stor *d;
  1559. {
  1560.     if (size1 == 1 && size2 > 2) {
  1561.     if (MC68020Opt) {
  1562.         outop("extb", size2, NULL, d);
  1563.         return;
  1564.     }
  1565.     outop("ext", 2, NULL, d);
  1566.     }
  1567.     outop("ext", size2, NULL, d);
  1568. }
  1569.  
  1570.  
  1571. void
  1572. asm_test(exp, s)
  1573. Exp *exp;
  1574. Stor *s;
  1575. {
  1576.     if (s->st_Flags & SF_BITFIELD) {
  1577.     asm_bftst(exp, s);
  1578.     return;
  1579.     }
  1580.  
  1581.     if (s->st_Type == ST_IntConst)
  1582.     {
  1583.     dbprintf(("asm_test: integer constant %ld", s->st_IntConst));
  1584.     Assert(0);
  1585.     }
  1586.     if ((s->st_Type == ST_Reg && s->st_RegNo >= RB_ADDR) || (s->st_Flags & SF_LEA) || ((s->st_Type == ST_RelLabel || s->st_Type == ST_RelName) && (s->st_Flags & SF_CODE))) {
  1587.     Stor stor;
  1588.     LockStorage(s);
  1589.     AllocDataRegister(&stor, s->st_Size);
  1590.     UnlockStorage(s);
  1591.     asm_move(exp, s, &stor);
  1592.     FreeRegister(&stor);
  1593.     return;
  1594.     }
  1595.     outop("tst", 0, NULL, s);
  1596. }
  1597.  
  1598. /*
  1599.  *  note: fp calls destroy scratch regs, so I have changed the moveq 0/scc
  1600.  *  to scc/ext
  1601.  */
  1602.  
  1603. void
  1604. asm_test_scc(Exp *exp, long typeid, Stor *s, short cond, Stor *d)
  1605. {
  1606.     short isfp = (typeid == TID_FLT) ? 1 : 0;
  1607.  
  1608.     if (SameStorage(s, d) || SameRegister(s, d) || d->st_Type != ST_Reg || d->st_RegNo >= RB_ADDR) {
  1609.     Stor t;
  1610.     LockStorage(s);
  1611.     AllocDataRegister(&t, d->st_Size);
  1612.     UnlockStorage(s);
  1613.  
  1614.     if (isfp) {
  1615.         asm_fptest(exp, s);
  1616.     } else {
  1617.         if (d->st_Size != 1)
  1618.         asm_movei(exp, 0, &t);
  1619.         asm_test(exp, s);
  1620.     }
  1621.     asm_sccb(exp, &t, cond, 0);
  1622.     if (isfp)
  1623.         extop(1, d->st_Size, &t);
  1624.  
  1625.     FreeRegister(&t);
  1626.     asm_move(exp, &t, d);
  1627.     } else {
  1628.     if (isfp) {
  1629.         asm_fptest(exp, s);
  1630.     } else {
  1631.         if (d->st_Size != 1)
  1632.         asm_movei(exp, 0, d);
  1633.         asm_test(exp, s);
  1634.     }
  1635.     asm_sccb(exp, d, cond, 0);
  1636.     if (isfp)
  1637.         extop(1, d->st_Size, d);
  1638.     }
  1639. }
  1640.  
  1641. void
  1642. asm_cond_scc(exp, typeid, s1, s2, pcond, d)
  1643. Exp *exp;
  1644. long typeid;
  1645. Stor *s1;
  1646. Stor *s2;
  1647. short *pcond;
  1648. Stor *d;
  1649. {
  1650.     short isfp = (typeid == TID_FLT) ? 1 : 0;
  1651.  
  1652.     if (SameStorage(s1, d) || SameStorage(s2, d) || d->st_Type != ST_Reg || d->st_RegNo >= RB_ADDR) {
  1653.     Stor t;
  1654.     LockStorage(s1);
  1655.     LockStorage(s2);
  1656.     AllocDataRegister(&t, d->st_Size);
  1657.     UnlockStorage(s1);
  1658.     UnlockStorage(s2);
  1659.  
  1660.     if (isfp) {
  1661.         asm_fpcmp(exp, s1, s2, pcond);     /*  if cmp reverses args it negates cond */
  1662.     } else {
  1663.         if (d->st_Size != 1)
  1664.         asm_movei(exp, 0, &t);
  1665.         asm_cmp(exp, s1, s2, pcond);     /*  if cmp reverses args it negates cond */
  1666.     }
  1667.     asm_sccb(exp, &t, *pcond, 0);
  1668.     if (isfp)
  1669.         extop(1, d->st_Size, &t);
  1670.  
  1671.     FreeRegister(&t);
  1672.     asm_move(exp, &t, d);
  1673.     } else {
  1674.  
  1675.     if (isfp) {
  1676.         asm_fpcmp(exp, s1, s2, pcond);   /*  if cmp reverses args it negates cond */
  1677.     } else {
  1678.         if (d->st_Size != 1)
  1679.         asm_movei(exp, 0, d);
  1680.         asm_cmp(exp, s1, s2, pcond);     /*  if cmp reverses args it negates cond */
  1681.     }
  1682.     asm_sccb(exp, d, *pcond, 0);
  1683.     if (isfp)
  1684.         extop(1, d->st_Size, d);
  1685.     }
  1686. }
  1687.  
  1688. void
  1689. asm_sccb(Exp *exp, Stor *d, short cond, short negative)
  1690. {
  1691.     char *str = "bad";
  1692.     long size;
  1693.  
  1694.     switch(cond) {
  1695.     case COND_LT:
  1696.     str = "slt";
  1697.     break;
  1698.     case COND_LTEQ:
  1699.     str = "sle";
  1700.     break;
  1701.     case COND_GT:
  1702.     str = "sgt";
  1703.     break;
  1704.     case COND_GTEQ:
  1705.     str = "sge";
  1706.     break;
  1707.     case COND_EQ:
  1708.     str = "seq";
  1709.     break;
  1710.     case COND_NEQ:
  1711.     str = "sne";
  1712.     break;
  1713.     case CF_UNS|COND_LT:
  1714.     str = "scs";
  1715.     break;
  1716.     case CF_UNS|COND_LTEQ:
  1717.     str = "sls";
  1718.     break;
  1719.     case CF_UNS|COND_GT:
  1720.     str = "shi";
  1721.     break;
  1722.     case CF_UNS|COND_GTEQ:
  1723.     str = "scc";
  1724.     break;
  1725.     case CF_UNS|COND_EQ:
  1726.     str = "seq";
  1727.     break;
  1728.     case CF_UNS|COND_NEQ:
  1729.     str = "sne";
  1730.     break;
  1731.  
  1732.     case -COND_LT:
  1733.     str = "sge";
  1734.     break;
  1735.     case -COND_LTEQ:
  1736.     str = "sgt";
  1737.     break;
  1738.     case -COND_GT:
  1739.     str = "sle";
  1740.     break;
  1741.     case -COND_GTEQ:
  1742.     str = "slt";
  1743.     break;
  1744.     case -COND_EQ:
  1745.     str = "sne";
  1746.     break;
  1747.     case -COND_NEQ:
  1748.     str = "seq";
  1749.     break;
  1750.     case -(CF_UNS|COND_LT):
  1751.     str = "scc";
  1752.     break;
  1753.     case -(CF_UNS|COND_LTEQ):
  1754.     str = "shi";
  1755.     break;
  1756.     case -(CF_UNS|COND_GT):
  1757.     str = "sls";
  1758.     break;
  1759.     case -(CF_UNS|COND_GTEQ):
  1760.     str = "scs";
  1761.     break;
  1762.     case -(CF_UNS|COND_EQ):
  1763.     str = "sne";
  1764.     break;
  1765.     case -(CF_UNS|COND_NEQ):
  1766.     str = "seq";
  1767.     break;
  1768.     case COND_BPL:
  1769.     str = "spl";
  1770.     break;
  1771.     case COND_BMI:
  1772.     str = "smi";
  1773.     break;
  1774.     default:
  1775.     dbprintf(("Unknown cond %d\n", cond));
  1776.     Assert(0);
  1777.     }
  1778.  
  1779.     size = d->st_Size;
  1780.     d->st_Size = 1;
  1781.     outop(str, 0, NULL, d);        /*    result 0 or -1.B */
  1782.  
  1783.     if (negative == 0)            /*    want positive r. */
  1784.     outop("neg", 1, NULL, d);
  1785.     d->st_Size = size;
  1786. }
  1787.  
  1788. void
  1789. asm_clr(exp, d)
  1790. Exp *exp;
  1791. Stor *d;
  1792. {
  1793.     asm_movei(exp, 0, d);
  1794. }
  1795.  
  1796. void
  1797. asm_movei(exp, val, d)
  1798. Exp *exp;
  1799. long val;
  1800. Stor *d;
  1801. {
  1802.     Stor stor;
  1803.  
  1804.     AllocConstStor(&stor, val, &LongType);
  1805.     stor.st_Size = d->st_Size;
  1806.     asm_move(exp, &stor, d);
  1807. }
  1808.  
  1809. /*
  1810.  *
  1811.  
  1812. void
  1813. asm_globlea(s, d)
  1814. Stor *s;
  1815. Stor *d;
  1816. {
  1817.     Assert(d->st_Type == ST_RelReg);
  1818.  
  1819.     printf("\tlea\t%s,A%c\n", StorToString(s, NULL), d->st_RegNo + '0' - RB_ADDR);
  1820. }
  1821.  *
  1822.  */
  1823.  
  1824.  
  1825. /*
  1826.  *  Arithmatic
  1827.  */
  1828.  
  1829. void
  1830. asm_neg(exp, s, d)
  1831. Exp *exp;
  1832. Stor *s;
  1833. Stor *d;
  1834. {
  1835.     Stor stor;
  1836.  
  1837.     Assert(s->st_Size == d->st_Size);
  1838.     if (SameStorage(s, d)) {
  1839.     outop("neg", 0, NULL, d);
  1840.     return;
  1841.     }
  1842.     AllocDataRegister(&stor, d->st_Size);
  1843.     asm_move(exp, s, &stor);
  1844.     outop("neg", 0, NULL, &stor);
  1845.     FreeRegister(&stor);
  1846.     asm_move(exp, &stor, d);
  1847. }
  1848.  
  1849. /*
  1850.  *  Attempt to optimize a 3-op by moving one source to the destination and then
  1851.  *  doing the operation with the other source to the destination.  Only do this
  1852.  *  if the destination is a register (else if it were memory it would result in
  1853.  *  longer instructions OR screw ups if the memory is an IO location)
  1854.  *
  1855.  *  becareful when the destination is an address register and s2 indirects
  1856.  *  through that self-same register!
  1857.  */
  1858.  
  1859. void
  1860. ThreeOp(exp, s1, s2, d, op)
  1861. Exp *exp;
  1862. Stor *s1;
  1863. Stor *s2;
  1864. Stor *d;
  1865. void (*op)(Exp *, Stor *, Stor *, Stor *);
  1866. {
  1867.     if (d->st_Type == ST_Reg && !(d->st_RegNo == s2->st_RegNo && s2->st_Type == ST_RelReg)) {
  1868.     LockStorage(s2);
  1869.     asm_move(exp, s1, d);
  1870.     UnlockStorage(s2);
  1871.     (*op)(exp, d, s2, d);
  1872.     } else {
  1873.     Stor tmp;
  1874.  
  1875.     LockStorage(s2);
  1876.     AllocDataRegister(&tmp, s1->st_Size);
  1877.     asm_move(exp, s1, &tmp);
  1878.     UnlockStorage(s2);
  1879.     (*op)(exp, &tmp, s2, &tmp);
  1880.     asm_move(exp, &tmp, d);
  1881.     FreeRegister(&tmp);
  1882.     }
  1883. }
  1884.  
  1885. void
  1886. asm_add(exp, s1, s2, d)
  1887. Exp *exp;
  1888. Stor *s1;
  1889. Stor *s2;
  1890. Stor *d;
  1891. {
  1892.     if (ImmStorage(s2)) {
  1893.     SWAPS(s1, s2);
  1894.     }
  1895.     if (SameStorage(s1,d)) {
  1896.     SWAPS(s1, s2);
  1897.     }
  1898.     if (!SameStorage(s2,d)) {    /*  3 operand inst  */
  1899.     ThreeOp(exp, s1, s2, d, asm_add);
  1900.     return;
  1901.     }
  1902.  
  1903.     if (s1->st_Flags & SF_LEA) {
  1904.     Stor t;
  1905.     LockStorage(s2);
  1906.     AllocAddrRegister(&t);
  1907.     asm_move(exp, s1, &t);
  1908.     UnlockStorage(s2);
  1909.     asm_add(exp, &t, s2, d);
  1910.     FreeRegister(&t);
  1911.     return;
  1912.     }
  1913.     if (d->st_Flags & SF_LEA)
  1914.     yerror(exp->ex_LexIdx, EFATAL_DEST_NOT_LVALUE);
  1915.  
  1916.     if (ImmStorage(s1)) {
  1917.     if (s1->st_Type != ST_IntConst) {   /*    #label    */
  1918.         outop("add", 0, s1, d);
  1919.         return;
  1920.     } else {
  1921.         if (s1->st_IntConst == 0) {
  1922.         if (!SameStorage(s2,d))
  1923.             asm_move(exp, s2, d);
  1924.         return;
  1925.         }
  1926.         if (s1->st_IntConst >= -8 && s1->st_IntConst <= 8) {
  1927.         if (s1->st_IntConst > 0) {
  1928.             outop("addq", 0, s1, d);
  1929.         } else {
  1930.             s1->st_IntConst = -s1->st_IntConst;
  1931.             outop("subq", 0, s1, d);
  1932.             s1->st_IntConst = -s1->st_IntConst;
  1933.         }
  1934.         } else if (d->st_Type == ST_Reg && d->st_RegNo >= RB_ADDR) {
  1935.         outop("adda", SizeFit(s1->st_IntConst), s1, d);
  1936.         } else {
  1937.         /*
  1938.          *  use moveq/add if possible
  1939.          */
  1940.         if (d->st_Size == 4 && s1->st_IntConst >= -128 && s1->st_IntConst < 128) {
  1941.             goto moveadd;
  1942.         } else {
  1943.             outop("add", 0, s1, d);
  1944.         }
  1945.         }
  1946.     }
  1947.     } else {    /*  not a constant  */
  1948.     Assert(s1->st_Size == d->st_Size);
  1949.     if ((s1->st_Type == ST_Reg && s1->st_RegNo < RB_ADDR) || d->st_Type == ST_Reg) {
  1950.         outop("add", 0, s1, d);
  1951.     } else {
  1952.         Stor stor;
  1953. moveadd:
  1954.         LockStorage(d);
  1955.         AllocDataRegister(&stor, d->st_Size);
  1956.         asm_move(exp, s1, &stor);
  1957.         UnlockStorage(d);
  1958.         asm_add(exp, &stor, d, d);
  1959.         FreeRegister(&stor);
  1960.     }
  1961.     }
  1962. }
  1963.  
  1964. void
  1965. asm_sub(exp, s1, s2, d)
  1966. Exp *exp;
  1967. Stor *s1;
  1968. Stor *s2;
  1969. Stor *d;
  1970. {
  1971.     if (!SameStorage(s1,d) && !SameStorage(s2,d)) {   /*  3 operand inst  */
  1972.     ThreeOp(exp, s1, s2, d, asm_sub);
  1973.     return;
  1974.     }
  1975.  
  1976.     if (s1->st_Flags & SF_LEA) {
  1977.     Stor t;
  1978.  
  1979.     LockStorage(s2);
  1980.     AllocAddrRegister(&t);
  1981.     asm_move(exp, s1, &t);
  1982.     UnlockStorage(s2);
  1983.     asm_sub(exp, &t, s2, d);
  1984.     FreeRegister(&t);
  1985.     return;
  1986.     }
  1987.  
  1988.     if (s2->st_Flags & SF_LEA) {
  1989.     Stor t;
  1990.  
  1991.     LockStorage(s1);
  1992.     AllocAddrRegister(&t);
  1993.     asm_move(exp, s2, &t);
  1994.     UnlockStorage(s1);
  1995.     asm_sub(exp, s1, &t, d);
  1996.     FreeRegister(&t);
  1997.     return;
  1998.     }
  1999.  
  2000.  
  2001.  
  2002.     if (s1->st_Type == ST_IntConst) {    /*  #val - s2    */
  2003.     Stor stor;
  2004.  
  2005.     Assert(SameStorage(s2,d));
  2006.     if (s2->st_Type == ST_Reg) {
  2007.         asm_neg(exp, d, d);
  2008.         asm_add(exp, s1, d, d);
  2009.         return;
  2010.     }
  2011.     LockStorage(s2);
  2012.     AllocDataRegister(&stor, d->st_Size);
  2013.     asm_move(exp, s1, &stor);
  2014.     UnlockStorage(s2);
  2015.     asm_sub(exp, &stor, s2, &stor);
  2016.     asm_move(exp, &stor, d);
  2017.     FreeRegister(&stor);
  2018.     return;
  2019.     }
  2020.     if (s2->st_Type == ST_IntConst) {    /*  s1 - #val    */
  2021.     Assert(SameStorage(s1,d));
  2022.     if (s2->st_IntConst == 0)
  2023.         return;
  2024.     if (s2->st_IntConst >= -8 && s2->st_IntConst <= 8) {
  2025.         if (s2->st_IntConst > 0) {
  2026.         outop("subq", 0, s2, d);
  2027.         } else {
  2028.         s2->st_IntConst = -s2->st_IntConst;
  2029.         outop("addq", 0, s2, d);
  2030.         s2->st_IntConst = -s2->st_IntConst;
  2031.         }
  2032.     } else if (d->st_Type == ST_Reg && d->st_RegNo >= RB_ADDR) {
  2033.         outop("suba", SizeFit(s2->st_IntConst), s2, d);
  2034.     } else {
  2035.         /*
  2036.          *    use moveq/sub if possible longword
  2037.          */
  2038.         if (d->st_Size == 4 && s2->st_IntConst >= -128 && s2->st_IntConst < 128) {
  2039.         goto movesub;
  2040.         } else {
  2041.         outop("sub", 0, s2, d);
  2042.         }
  2043.     }
  2044.     return;
  2045.     }
  2046.     if (SameStorage(s1,d)) {        /*  d = d - s2    */
  2047.     if (d->st_Type == ST_Reg || (s2->st_Type == ST_Reg && s2->st_RegNo < RB_ADDR)) {
  2048.         outop("sub", 0, s2, d);
  2049.     } else {
  2050.         Stor stor;
  2051. movesub:
  2052.         LockStorage(d);
  2053.         AllocDataRegister(&stor, d->st_Size);
  2054.         asm_move(exp, s2, &stor);
  2055.         UnlockStorage(d);
  2056.         asm_sub(exp, d, &stor, d);
  2057.         FreeRegister(&stor);
  2058.     }
  2059.     } else {                /*  s2 == d:  d = s1 - d  */
  2060.     Stor stor;
  2061.     if (d->st_Type == ST_Reg) {
  2062.         asm_neg(exp, d, d);
  2063.         outop("add", 0, s1, d);
  2064.         return;
  2065.     }
  2066.     LockStorage(d);
  2067.     AllocDataRegister(&stor, d->st_Size);
  2068.     asm_move(exp, s1, &stor);
  2069.     UnlockStorage(d);
  2070.     asm_sub(exp, &stor, d, &stor);
  2071.     asm_move(exp, &stor, d);
  2072.     FreeRegister(&stor);
  2073.     }
  2074.     return;
  2075. }
  2076.  
  2077. /*
  2078.  *  eadnok  ==    0   Dn,<ea>
  2079.  *        ==    1   Dn,<ea> or <ea>,Dn
  2080.  */
  2081.  
  2082. Local void
  2083. asm_gen_logic_class(exp, str, bitstr, bitinverse, s1, s2, d, eadnok)
  2084. Exp *exp;
  2085. char *str;
  2086. char *bitstr;
  2087. Stor *s1;
  2088. Stor *s2;
  2089. Stor *d;
  2090. long bitinverse;
  2091. long eadnok;
  2092. {
  2093.     if ((s1->st_Flags & SF_LEA) || (s1->st_Type == ST_Reg && s1->st_RegNo >= RB_ADDR)) {
  2094.     Stor d1;
  2095.  
  2096.     LockStorage(s2);
  2097.     AllocDataRegister(&d1, 4);
  2098.     UnlockStorage(s2);
  2099.     asm_move(exp, s1, &d1);
  2100.     asm_gen_logic_class(exp, str, bitstr, bitinverse, &d1, s2, d, eadnok);
  2101.     FreeRegister(&d1);
  2102.     return;
  2103.     }
  2104.     if ((s2->st_Flags & SF_LEA) || (s2->st_Type == ST_Reg && s2->st_RegNo >= RB_ADDR)) {
  2105.     Stor d2;
  2106.  
  2107.     LockStorage(s1);
  2108.     AllocDataRegister(&d2, 4);
  2109.     UnlockStorage(s1);
  2110.     asm_move(exp, s2, &d2);
  2111.     asm_gen_logic_class(exp, str, bitstr, bitinverse, s1, &d2, d, eadnok);
  2112.     FreeRegister(&d2);
  2113.     return;
  2114.     }
  2115.     if (d->st_Type == ST_Reg && d->st_RegNo >= RB_ADDR) {   /*    addr reg is dest */
  2116.     Stor td;
  2117.  
  2118.     AllocDataRegister(&td, d->st_Size);
  2119.     asm_gen_logic_class(exp, str, bitstr, bitinverse, s1, s2, &td, eadnok);
  2120.     asm_move(exp, &td, d);
  2121.     FreeRegister(&td);
  2122.     return;
  2123.     }
  2124.  
  2125.     if (SameStorage(s2, d)) {
  2126.     SWAPS(s1,s2);
  2127.     }
  2128.     if (SameStorage(s1, d)) {
  2129.     if (s2->st_Type == ST_IntConst) {
  2130.         short n;
  2131.         if ((n = PowerOfTwo(s2->st_IntConst ^ bitinverse)) >= 0) {
  2132.         Stor con;
  2133.         long size;
  2134.         AllocConstStor(&con, n, &LongType);
  2135.         if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR) {
  2136.             outop(bitstr, 4, &con, d);
  2137.         } else {
  2138.             long bits = d->st_Size * 8;
  2139.  
  2140.             con.st_IntConst &= 7;
  2141.             Assert((d->st_Flags & SF_LEA) == 0);
  2142.             switch(d->st_Type) {
  2143.             case ST_PtrConst:
  2144.             case ST_RelArg:
  2145.             case ST_RelReg:
  2146.             case ST_RegIndex:
  2147.             case ST_RelLabel:
  2148.             case ST_RelName:
  2149.             if (n < bits) {
  2150.                 size = d->st_Size;
  2151.                 d->st_Size = 1;
  2152.                 d->st_Offset += (bits-1-n) >> 3;
  2153.                 outop(bitstr, 1, &con, d);
  2154.                 d->st_Offset -= (bits-1-n) >> 3;
  2155.                 d->st_Size = size;
  2156.             } else {
  2157.                 yerror(exp->ex_LexIdx, EWARN_CONSTANT_OUT_OF_RANGE, n);
  2158.             }
  2159.             return;
  2160.             default:
  2161.             dbprintf(("Illegal destination type %d\n", d->st_Type));
  2162.             Assert(0);
  2163.             }
  2164.         }
  2165.         return;
  2166.         }
  2167.  
  2168.         /*
  2169.          *    s2 is an integer constant.  If the destination argument is a
  2170.          *    long and s2 is in the moveq range it is faster and smaller to
  2171.          *    move the constant into a data register first.
  2172.          */
  2173.  
  2174.         if (d->st_Size == 4 && s2->st_IntConst >= -128 && s2->st_IntConst < 128) {
  2175.         Stor tmp;
  2176.  
  2177.         LockStorage(d);
  2178.         AllocDataRegister(&tmp, d->st_Size);
  2179.         UnlockStorage(d);
  2180.         asm_move(exp, s2, &tmp);
  2181.         outop(str, 0, &tmp, d);
  2182.         FreeRegister(&tmp);
  2183.         } else {
  2184.         outop(str, 0, s2, d);
  2185.         }
  2186.         return;
  2187.     } else if (s2->st_Type == ST_Reg && s2->st_RegNo < RB_ADDR) {
  2188.         outop(str, 0, s2, d);
  2189.         return;
  2190.     } else if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR) {
  2191.         if (eadnok) {
  2192.         outop(str, 0, s2, d);
  2193.         return;
  2194.         }
  2195.     }
  2196.     }
  2197.     if (d->st_Type == ST_Reg) {
  2198.     if (s1->st_Type == ST_Reg && s1->st_RegNo < RB_ADDR && !SameStorage(s1,d)) {
  2199.         LockStorage(s1);
  2200.         asm_move(exp, s2, d);
  2201.         UnlockStorage(s1);
  2202.         outop(str, 0, s1, d);
  2203.         return;
  2204.     } else if (s2->st_Type == ST_Reg && s2->st_RegNo < RB_ADDR && !SameStorage(s2,d)) {
  2205.         LockStorage(s2);
  2206.         asm_move(exp, s1, d);
  2207.         UnlockStorage(s2);
  2208.         outop(str, 0, s2, d);
  2209.         return;
  2210.     }
  2211.     }
  2212.  
  2213.     /*
  2214.      *    better to load the constant into a register, long operations will
  2215.      *    benefit when we can use moveq.    We have to a move anyway so otherwise
  2216.      *    it does not matter whether the constant is moved or the other operand.
  2217.      */
  2218.  
  2219.     if (s1->st_Type == ST_IntConst)
  2220.     SWAPS(s1,s2);
  2221.     {
  2222.     Stor tmp;
  2223.     short useD;
  2224.  
  2225.     LockStorage(s1);
  2226.     if (d->st_Type == ST_Reg && d->st_RegNo < RB_ADDR && !SameRegister(s1, d)) {
  2227.         useD = 1;
  2228.         asm_move(exp, s2, d);
  2229.     } else {
  2230.         useD = 0;
  2231.         AllocDataRegister(&tmp, s2->st_Size);
  2232.         asm_move(exp, s2, &tmp);
  2233.     }
  2234.     UnlockStorage(s1);
  2235.  
  2236.     if ((s1->st_Type == ST_Reg && s1->st_RegNo >= RB_ADDR) || (eadnok == 0 && s1->st_Type != ST_Reg)) {
  2237.         Stor tmp2;
  2238.         AllocDataRegister(&tmp2, s1->st_Size);
  2239.         asm_move(exp, s1, &tmp2);
  2240.         if (useD)
  2241.         outop(str, 0, &tmp2, d);
  2242.         else
  2243.         outop(str, 0, &tmp2, &tmp);
  2244.         FreeRegister(&tmp2);
  2245.     } else {
  2246.         if (useD)
  2247.         outop(str, 0, s1, d);
  2248.         else
  2249.         outop(str, 0, s1, &tmp);
  2250.     }
  2251.     if (useD == 0) {
  2252.         asm_move(exp, &tmp, d);
  2253.         FreeRegister(&tmp);
  2254.     }
  2255.     }
  2256. }
  2257.  
  2258. void
  2259. asm_xor(exp, s1, s2, d)
  2260. Exp *exp;
  2261. Stor *s1;
  2262. Stor *s2;
  2263. Stor *d;
  2264. {
  2265.     if (s2->st_Type == ST_IntConst && s2->st_IntConst == -1) {
  2266.     Stor *t = s1;
  2267.     s1 = s2;
  2268.     s2 = t;
  2269.     }
  2270.     if (s1->st_Type == ST_IntConst && s1->st_IntConst == -1) {
  2271.     if (SameStorage(s2, d)) {
  2272.         outop("not", d->st_Size, NULL, d);
  2273.     } else {
  2274.         Stor t;
  2275.  
  2276.         AllocDataRegister(&t, s2->st_Size);
  2277.         asm_move(exp, s2, &t);
  2278.         outop("not", t.st_Size, NULL, &t);
  2279.         asm_move(exp, &t, d);
  2280.         FreeRegister(&t);
  2281.     }
  2282.     return;
  2283.     }
  2284.     asm_gen_logic_class(exp, "eor", "bchg", 0, s1, s2, d, 0);
  2285. }
  2286.  
  2287. void
  2288. asm_and(exp, s1, s2, d)
  2289. Exp *exp;
  2290. Stor *s1;
  2291. Stor *s2;
  2292. Stor *d;
  2293. {
  2294.     asm_gen_logic_class(exp, "and", "bclr", -1, s1, s2, d, 1);
  2295. }
  2296.  
  2297. void
  2298. asm_or(exp, s1, s2, d)
  2299. Exp *exp;
  2300. Stor *s1;
  2301. Stor *s2;
  2302. Stor *d;
  2303. {
  2304.     asm_gen_logic_class(exp, "or", "bset", 0, s1, s2, d, 1);
  2305. }
  2306.  
  2307. /*
  2308.  *  test / and optimization, note that btst doesn't work with address
  2309.  *  registers so can't optimize for that (asm_gen_logic.. will produce
  2310.  *  illegal output if we were to try)
  2311.  */
  2312.  
  2313. void
  2314. asm_test_and(exp, s1, s2)
  2315. Exp *exp;
  2316. Stor *s1;
  2317. Stor *s2;
  2318. {
  2319.     Stor d;
  2320.  
  2321.     if (s2->st_Type == ST_IntConst)
  2322.     SWAPS(s1,s2);
  2323.     if (s1->st_Type == ST_IntConst && PowerOfTwo(s1->st_IntConst) >= 0) {
  2324.     if (s2->st_Type != ST_Reg || s2->st_RegNo < RB_ADDR) {
  2325.         asm_gen_logic_class(exp, "tstand-bad-1", "btst", 0, s1, s2, s2, 1);
  2326.         return;
  2327.     }
  2328.     }
  2329.     if (s1->st_Size != s2->st_Size)
  2330.     yerror(exp->ex_LexIdx, EERROR_SIZE_MISMATCH, s1->st_Size, s2->st_Size);
  2331.     AllocDataRegister(&d, s1->st_Size);
  2332.     asm_gen_logic_class(exp, "and", "tstand-bad-2", 0, s1, s2, &d, 1);
  2333.     FreeRegister(&d);
  2334. }
  2335.  
  2336. /*
  2337.  *  Switch on storage s.    Cases are sorted.  Cases outside the
  2338.  *                storage range of the storage are
  2339.  *                deleted.
  2340.  *
  2341.  *  (1) Table lookup
  2342.  *  (2) Switch List
  2343.  *  (3) Binary search with switch list sub segments
  2344.  */
  2345.  
  2346. void
  2347. asm_switch(exp, num, cases, labels, deflabel)
  2348. Exp *exp;
  2349. long num;
  2350. long *cases;
  2351. long *labels;
  2352. long deflabel;
  2353. {
  2354.     long minBound, maxBound;
  2355.     Stor con;
  2356.     Stor dtmp;
  2357.     Stor *s = &exp->ex_Stor;
  2358.  
  2359.     if (num == 0)
  2360.     return;
  2361.  
  2362.     minBound = 0x80000000;
  2363.     maxBound = 0x7FFFFFFF;
  2364.  
  2365.     if (s->st_Flags & SF_UNSIGNED) {
  2366.     if (s->st_Size == 1) {
  2367.         minBound = 0;
  2368.         maxBound = 255;
  2369.     } else if (s->st_Size == 2) {
  2370.         minBound = 0;
  2371.         maxBound = 65535;
  2372.     }
  2373.     } else {
  2374.     if (s->st_Size == 1) {
  2375.         minBound = -128;
  2376.         maxBound = 127;
  2377.     } else if (s->st_Size == 2) {
  2378.         minBound = -32768;
  2379.         maxBound = 32767;
  2380.     }
  2381.     }
  2382.  
  2383.     /*
  2384.      *    Sort the cases, delete out of bounds cases
  2385.      */
  2386.  
  2387.     SortCases(exp, cases, labels, num);
  2388.  
  2389.     while (num && cases[0] < minBound) {
  2390.     yerror(exp->ex_LexIdx, EWARN_CONSTANT_OUT_OF_RANGE, cases[0]);
  2391.     --num;
  2392.     ++cases;
  2393.     ++labels;
  2394.     }
  2395.     while (num && cases[num-1] > maxBound) {
  2396.     yerror(exp->ex_LexIdx, EWARN_CONSTANT_OUT_OF_RANGE, cases[num-1]);
  2397.     --num;
  2398.     }
  2399.     if (num == 0) {
  2400.     asm_branch(deflabel);
  2401.     return;
  2402.     }
  2403.     AllocConstStor(&con, 0, &LongType);
  2404.  
  2405.     if (num == 1) {
  2406.     short cond = COND_EQ;
  2407.     con.st_IntConst = cases[0];
  2408.     con.st_Size = s->st_Size;
  2409.     asm_cmp(exp, s, &con, &cond);
  2410.     asm_condbra(cond, labels[0]);
  2411.     asm_branch(deflabel);
  2412.     return;
  2413.     }
  2414.  
  2415.     /*
  2416.      *    If switching on an unsigned quantity convert the values to
  2417.      *    equivalent signed quantities because this is an assumption
  2418.      *    of the switch code.
  2419.      */
  2420.  
  2421.     if ((s->st_Flags & SF_UNSIGNED) && s->st_Size != 4) {
  2422.     long i;
  2423.  
  2424.     for (i = 0; i < num; ++i) {
  2425.         if (s->st_Size == 1)
  2426.         cases[i] = (char)cases[i];
  2427.         else if (s->st_Size == 2)
  2428.         cases[i] = (short)cases[i];
  2429.     }
  2430.     }
  2431.     SortCases(exp, cases, labels, num);
  2432.  
  2433.     minBound = cases[0];    /*  boundry conditions    */
  2434.     maxBound = cases[num-1];
  2435.  
  2436.     if (num > 8 && (ulong)(maxBound - minBound) < num * 2) {
  2437.     long label = AllocLabel();
  2438.     long i;
  2439.     long j;
  2440.     short cond;
  2441.  
  2442.     AllocDataRegister(&dtmp, s->st_Size);
  2443.  
  2444.     asm_move(exp, s, &dtmp);
  2445.     if (minBound) {
  2446.         con.st_IntConst = minBound;
  2447.         con.st_Size = s->st_Size;
  2448.         asm_sub(exp, &dtmp, &con, &dtmp);
  2449.     }
  2450.  
  2451.     /*
  2452.      *  range test
  2453.      */
  2454.  
  2455.     cond = COND_GT | CF_UNS;
  2456.     con.st_IntConst = maxBound - minBound;
  2457.     con.st_Size = s->st_Size;
  2458.     asm_cmp(exp, &dtmp, &con, &cond);
  2459.     asm_condbra(cond, deflabel);
  2460.  
  2461.     /*
  2462.      *  size = 1 case, then force size to 2. (can handle 8192 cases) XXX?
  2463.      */
  2464.  
  2465.     if (s->st_Size == 1) {
  2466.         con.st_IntConst = 0x00FF;
  2467.         outop("and", 2, &con, &dtmp);
  2468.     }
  2469.     dtmp.st_Size = 2;
  2470.  
  2471.     printf("\tasl.w\t#2,D%c\n", dtmp.st_RegNo + '0');
  2472.     printf("\tjmp\tl%ld(pc,d%d.w)\n", label, dtmp.st_RegNo);
  2473.  
  2474.     asm_label(label);
  2475.     j = 0;
  2476.     for (i = minBound; i <= maxBound; ++i) {
  2477.         while (cases[j] != i) {
  2478.         printf("\tjmp\tl%ld(pc)\n", deflabel);
  2479.         if (i == maxBound || j > num)
  2480.         {
  2481.             dbprintf(("in switch, case [%ld] %ld", j, cases[j]));
  2482.             Assert(0);
  2483.         }
  2484.         ++i;
  2485.         }
  2486.         printf("\tjmp\tl%ld(pc)\n", labels[j++]);
  2487.     }
  2488.     if (j != num)
  2489.     {
  2490.         dbprintf(("in switch, aryend %ld/%ld", j, num));
  2491.         Assert(0);
  2492.     }
  2493.     FreeRegister(&dtmp);
  2494.     } else {
  2495.     /*
  2496.      *  subtract / branch
  2497.      */
  2498.  
  2499.     AllocDataRegister(&dtmp, s->st_Size);
  2500.     asm_move(exp, s, &dtmp);
  2501.  
  2502.     con.st_Size = s->st_Size;
  2503.  
  2504.     SubDivideSwitch(exp, &dtmp, &con, 0, 0, num, deflabel, cases, labels);
  2505.     FreeRegister(&dtmp);
  2506.     }
  2507.  
  2508.     /*
  2509.      *    If switching on an unsigned quantity we converted the quantities
  2510.      *    to signed for the switch op, but due to the possibility of
  2511.      *    retries we have to convert the objects back before returning.
  2512.      */
  2513.  
  2514.     if ((s->st_Flags & SF_UNSIGNED) && s->st_Size != 4) {
  2515.     long i;
  2516.  
  2517.     for (i = 0; i < num; ++i) {
  2518.         if (s->st_Size == 1)
  2519.         cases[i] = (ubyte)cases[i];
  2520.         else if (s->st_Size == 2)
  2521.         cases[i] = (uword)cases[i];
  2522.     }
  2523.     }
  2524.  
  2525. }
  2526.  
  2527. /*
  2528.  *  SubDivideSwitch()
  2529.  *
  2530.  *  Values are signed quantities
  2531.  *
  2532.  *  This is used to execute a binary subdivision on a switch.  If the
  2533.  *  last case tested was j then our current zero is j.
  2534.  *
  2535.  *  To test case n- next we must add 5, bcs for higher cases and
  2536.  *  bcc for lower cases
  2537.  *
  2538.  *  To test case n+ next we must subtract 5, bcc for higher cases and
  2539.  *  bcs for lower cases
  2540.  *
  2541.  *        S
  2542.  *        .
  2543.  *        n-        5    -5
  2544.  *        .
  2545.  *        N  <---- j    10    0
  2546.  *        .
  2547.  *        n+        15   +5
  2548.  *        .
  2549.  *        X
  2550.  */
  2551.  
  2552. void
  2553. SubDivideSwitch(exp, s, c, j, is, ie, deflabel, cases, labels)
  2554. Exp *exp;
  2555. Stor *s;
  2556. Stor *c;
  2557. long j;
  2558. long is, ie, deflabel;
  2559. long *cases;
  2560. long *labels;
  2561. {
  2562.     long i;
  2563.     long ic;
  2564.     long v;
  2565.     short high_cond;
  2566.  
  2567.     if (ie - is <= 4) {
  2568.     for (i = is; i < ie; ++i) {
  2569.         c->st_IntConst = (cases[i] - j);   /*  amount to subtract */
  2570.         if (c->st_IntConst)
  2571.         asm_sub(exp, s, c, s);
  2572.         else
  2573.         asm_test(exp, s);
  2574.         asm_condbra(COND_EQ, labels[i]);
  2575.         j += c->st_IntConst;
  2576.     }
  2577.     asm_branch(deflabel);
  2578.     return;
  2579.     }
  2580.  
  2581.     /*
  2582.      *    Current center point is j, find new center point.  If the absolute
  2583.      *    range is greater then the maximum positive signed quantity the
  2584.      *    storage can hold we use a CMP, otherwise we ADD or SUB to the
  2585.      *    new center point.
  2586.      *
  2587.      *    When we use compare we must use BGE style branches since we are
  2588.      *    doing a signed compare for signed ranging.  When we use an
  2589.      *    add or subtract we use BPL to get to the greater half (ignoring
  2590.      *    overflow) and are guarenteed the range will, by that time,
  2591.      *    be less then 2^(N-1)
  2592.      */
  2593.  
  2594.     ic = (is + ie) >> 1;        /*  center point (index)    */
  2595.     v = 1 << ((s->st_Size << 3) - 1);    /*  max pos integer + 1     */
  2596.  
  2597.     if ((ulong)(cases[ic] - cases[is]) >= (ulong)v || (ulong)(cases[ie-1] - cases[ic]) >= (ulong)v) {
  2598.     high_cond = COND_GTEQ;
  2599.     c->st_IntConst = cases[ic];
  2600.     asm_cmp(exp, s, c, &high_cond);
  2601.     /*
  2602.      *  j doesn't change (remains 0)
  2603.      */
  2604.     } else {
  2605.     c->st_IntConst = j - cases[ic];
  2606.     if (c->st_IntConst)
  2607.         asm_add(exp, s, c, s);
  2608.     else
  2609.         asm_test(exp, s);
  2610.     j = cases[ic];
  2611.     high_cond = COND_BPL;
  2612.     }
  2613.  
  2614.     asm_condbra(COND_EQ, labels[ic]);
  2615.  
  2616.     i = AllocLabel();
  2617.  
  2618.     asm_condbra(high_cond, i);
  2619.  
  2620. #ifdef NOTDEF
  2621.     if (high_cond == COND_GTEQ)
  2622.     printf("\tbpl\tl%ld\n", i);
  2623.     else
  2624.     printf("\tbmi\tl%ld\n", i);
  2625. #endif
  2626.  
  2627.     SubDivideSwitch(exp, s, c, j, is, ic, deflabel, cases, labels);
  2628.     asm_label(i);
  2629.     SubDivideSwitch(exp, s, c, j, ic+1, ie, deflabel, cases, labels);
  2630. }
  2631.  
  2632. #define SWAPL(l1,l2)    { long lt = l1; l1 = l2; l2 = lt; }
  2633.  
  2634. Local void
  2635. SortCases(exp, cases, labels, num)
  2636. Exp *exp;
  2637. long *cases;
  2638. long *labels;
  2639. long num;
  2640. {
  2641.     long sv;
  2642.     long si;
  2643.     long sj;
  2644.  
  2645. loop:
  2646.     switch(num) {
  2647.     case -1:
  2648.     case 0:
  2649.     case 1:
  2650.     break;
  2651.     case 2:
  2652.     if (cases[0] > cases[1]) {
  2653.         SWAPL(cases[0], cases[1]);
  2654.         SWAPL(labels[0], labels[1]);
  2655.     }
  2656.     break;
  2657.     default:
  2658.     sv = cases[num>>1];    /*  split value */
  2659.     for (si = sj = 0; si < num; ++si) {
  2660.         if (cases[si] < sv) {
  2661.         SWAPL(cases[si], cases[sj]);
  2662.         SWAPL(labels[si], labels[sj]);
  2663.         ++sj;
  2664.         }
  2665.     }
  2666.     if (sj == 0) {        /*  sv smallest */
  2667.         if ((si = num >> 1) != 0) {
  2668.         SWAPL(cases[0], cases[si]);
  2669.         SWAPL(labels[0], labels[si]);
  2670.         }
  2671.         ++cases;
  2672.         ++labels;
  2673.         --num;
  2674.         goto loop;
  2675.     }
  2676.     if (sj == num) {    /*  sv largtest */
  2677.         if ((si = num >> 1) != num - 1) {
  2678.         SWAPL(cases[num-1], cases[si]);
  2679.         SWAPL(labels[num-1], labels[si]);
  2680.         }
  2681.         --num;
  2682.         goto loop;
  2683.     }
  2684.     SortCases(exp, cases, labels, sj);
  2685.     SortCases(exp, cases + sj, labels + sj, num - sj);
  2686.     }
  2687.     {
  2688.     long *cp = cases;
  2689.  
  2690.     sv = *cp;
  2691.     for (si = num - 2; si >= 0; --si, ++cp) {
  2692.         sj = cp[1];
  2693.         if (sv == sj)
  2694.         break;
  2695.         sv = sj;
  2696.     }
  2697.     }
  2698.     if (si >= 0)
  2699.     yerror(exp->ex_LexIdx, EERROR_CASE_REPEATED, sv, sv);
  2700. }
  2701.  
  2702.  
  2703. long
  2704. SizeFit(v)
  2705. long v;
  2706. {
  2707.     if (v >= -32768 && v < 32768)
  2708.     return(2);
  2709.     return(4);
  2710. }
  2711.  
  2712. long
  2713. SizeFitSU(v, s)
  2714. long v;
  2715. Stor *s;
  2716. {
  2717.     if (s->st_Flags & SF_UNSIGNED) {
  2718.     if ((ulong)v < 65536)
  2719.         return(2);
  2720.     } else {
  2721.     if (v >= -32768 && v < 32768)
  2722.         return(2);
  2723.     }
  2724.     return(4);
  2725. }
  2726.  
  2727. void
  2728. asm_end()
  2729. {
  2730.     long cp, ep;
  2731.  
  2732.     printf("\tEND\n");
  2733.     cp = ftell(stdout);
  2734.     fseek(stdout, 0L, 2);
  2735.     ep = ftell(stdout);
  2736.     if (cp > 0 && ep > 0 && cp < ep) {
  2737.     fseek(stdout, cp, 0);
  2738.     while (cp < ep) {
  2739.         fputc('\n', stdout);
  2740.         ++cp;
  2741.     }
  2742.     }
  2743. }
  2744.